From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- .../accessibility/AccessibleControlShape.cxx | 881 ++ .../accessibility/AccessibleEmptyEditSource.cxx | 329 + .../accessibility/AccessibleEmptyEditSource.hxx | 93 + .../accessibility/AccessibleFrameSelector.cxx | 382 + .../accessibility/AccessibleGraphicShape.cxx | 152 + svx/source/accessibility/AccessibleOLEShape.cxx | 180 + svx/source/accessibility/AccessibleShape.cxx | 1343 +++ svx/source/accessibility/AccessibleShapeInfo.cxx | 63 + .../accessibility/AccessibleShapeTreeInfo.cxx | 117 + .../accessibility/AccessibleTextEventQueue.cxx | 92 + .../accessibility/AccessibleTextEventQueue.hxx | 90 + svx/source/accessibility/AccessibleTextHelper.cxx | 1786 ++++ svx/source/accessibility/ChildrenManager.cxx | 115 + svx/source/accessibility/ChildrenManagerImpl.cxx | 1040 +++ svx/source/accessibility/ChildrenManagerImpl.hxx | 495 ++ svx/source/accessibility/DescriptionGenerator.cxx | 201 + .../accessibility/GraphCtlAccessibleContext.cxx | 772 ++ svx/source/accessibility/ShapeTypeHandler.cxx | 307 + svx/source/accessibility/SvxShapeTypes.cxx | 165 + svx/source/accessibility/charmapacc.cxx | 588 ++ svx/source/accessibility/lookupcolorname.cxx | 117 + svx/source/accessibility/lookupcolorname.hxx | 57 + .../accessibility/svxpixelctlaccessiblecontext.cxx | 469 ++ .../accessibility/svxrectctaccessiblecontext.cxx | 643 ++ svx/source/core/extedit.cxx | 204 + svx/source/core/graphichelper.cxx | 423 + svx/source/customshapes/EnhancedCustomShape2d.cxx | 3040 +++++++ svx/source/customshapes/EnhancedCustomShape3d.cxx | 815 ++ svx/source/customshapes/EnhancedCustomShape3d.hxx | 74 + .../customshapes/EnhancedCustomShapeEngine.cxx | 511 ++ .../customshapes/EnhancedCustomShapeFontWork.cxx | 903 +++ .../customshapes/EnhancedCustomShapeFontWork.hxx | 42 + .../EnhancedCustomShapeFunctionParser.cxx | 1160 +++ .../customshapes/EnhancedCustomShapeGeometry.cxx | 8563 ++++++++++++++++++++ .../customshapes/EnhancedCustomShapeHandle.cxx | 94 + .../customshapes/EnhancedCustomShapeHandle.hxx | 57 + .../customshapes/EnhancedCustomShapeTypeNames.cxx | 567 ++ svx/source/dialog/AccessibilityCheckDialog.cxx | 64 + svx/source/dialog/ClassificationCommon.cxx | 125 + svx/source/dialog/ClassificationDialog.cxx | 693 ++ svx/source/dialog/ClassificationEditView.cxx | 81 + svx/source/dialog/ClassificationEditView.hxx | 57 + svx/source/dialog/SafeModeDialog.cxx | 342 + svx/source/dialog/SafeModeDialog.hxx | 67 + svx/source/dialog/SafeModeUI.cxx | 81 + svx/source/dialog/SpellDialogChildWindow.cxx | 90 + svx/source/dialog/SvxNumOptionsTabPageHelper.cxx | 88 + svx/source/dialog/_bmpmask.cxx | 1057 +++ svx/source/dialog/_contdlg.cxx | 675 ++ svx/source/dialog/charmap.cxx | 1872 +++++ svx/source/dialog/compressgraphicdialog.cxx | 432 + svx/source/dialog/connctrl.cxx | 310 + svx/source/dialog/contimp.hxx | 132 + svx/source/dialog/contwnd.cxx | 271 + svx/source/dialog/contwnd.hxx | 70 + svx/source/dialog/crashreportdlg.cxx | 105 + svx/source/dialog/crashreportdlg.hxx | 38 + svx/source/dialog/crashreportui.cxx | 81 + svx/source/dialog/ctredlin.cxx | 1023 +++ svx/source/dialog/databaseregistrationui.cxx | 45 + svx/source/dialog/dialcontrol.cxx | 479 ++ svx/source/dialog/dialmgr.cxx | 33 + svx/source/dialog/dlgctl3d.cxx | 1182 +++ svx/source/dialog/dlgctrl.cxx | 1459 ++++ svx/source/dialog/dlgunit.hxx | 54 + svx/source/dialog/dlgutil.cxx | 81 + svx/source/dialog/docrecovery.cxx | 1099 +++ svx/source/dialog/fntctrl.cxx | 1108 +++ svx/source/dialog/fontwork.cxx | 794 ++ svx/source/dialog/framelink.cxx | 431 + svx/source/dialog/framelinkarray.cxx | 1290 +++ svx/source/dialog/frmdirlbox.cxx | 32 + svx/source/dialog/frmsel.cxx | 1277 +++ svx/source/dialog/graphctl.cxx | 841 ++ svx/source/dialog/grfflt.cxx | 294 + svx/source/dialog/hdft.cxx | 1060 +++ svx/source/dialog/hexcolorcontrol.cxx | 112 + svx/source/dialog/hyperdlg.cxx | 85 + svx/source/dialog/imapdlg.cxx | 733 ++ svx/source/dialog/imapimp.hxx | 50 + svx/source/dialog/imapwnd.cxx | 748 ++ svx/source/dialog/imapwnd.hxx | 141 + svx/source/dialog/langbox.cxx | 503 ++ svx/source/dialog/linkwarn.cxx | 57 + svx/source/dialog/measctrl.cxx | 157 + svx/source/dialog/optgrid.cxx | 289 + svx/source/dialog/page.hrc | 99 + svx/source/dialog/pagectrl.cxx | 406 + svx/source/dialog/pagenumberlistbox.cxx | 52 + svx/source/dialog/papersizelistbox.cxx | 74 + svx/source/dialog/paraprev.cxx | 214 + svx/source/dialog/passwd.cxx | 91 + svx/source/dialog/relfld.cxx | 103 + svx/source/dialog/rlrcitem.cxx | 148 + svx/source/dialog/rlrcitem.hxx | 42 + svx/source/dialog/rubydialog.cxx | 890 ++ svx/source/dialog/rulritem.cxx | 731 ++ svx/source/dialog/samecontentlistbox.cxx | 39 + svx/source/dialog/searchcharmap.cxx | 430 + svx/source/dialog/spacinglistbox.cxx | 76 + svx/source/dialog/srchctrl.cxx | 71 + svx/source/dialog/srchctrl.hxx | 39 + svx/source/dialog/srchdlg.cxx | 2452 ++++++ svx/source/dialog/strarray.cxx | 98 + svx/source/dialog/svxbmpnumvalueset.cxx | 524 ++ svx/source/dialog/svxdlg.cxx | 32 + svx/source/dialog/svxgrahicitem.cxx | 39 + svx/source/dialog/svxruler.cxx | 3559 ++++++++ svx/source/dialog/swframeexample.cxx | 714 ++ svx/source/dialog/swframeposstrings.cxx | 38 + svx/source/dialog/txencbox.cxx | 274 + svx/source/dialog/txenctab.cxx | 49 + svx/source/dialog/weldeditview.cxx | 1482 ++++ svx/source/engine3d/camera3d.cxx | 180 + svx/source/engine3d/cube3d.cxx | 157 + svx/source/engine3d/deflt3d.cxx | 56 + svx/source/engine3d/dragmt3d.cxx | 732 ++ svx/source/engine3d/e3dsceneupdater.cxx | 111 + svx/source/engine3d/e3dundo.cxx | 91 + svx/source/engine3d/extrud3d.cxx | 223 + svx/source/engine3d/float3d.cxx | 2949 +++++++ svx/source/engine3d/helperhittest3d.cxx | 277 + svx/source/engine3d/helperminimaldepth3d.cxx | 201 + svx/source/engine3d/helperminimaldepth3d.hxx | 48 + svx/source/engine3d/lathe3d.cxx | 205 + svx/source/engine3d/obj3d.cxx | 625 ++ svx/source/engine3d/objfac3d.cxx | 73 + svx/source/engine3d/polygn3d.cxx | 248 + svx/source/engine3d/scene3d.cxx | 909 +++ svx/source/engine3d/sphere3d.cxx | 153 + svx/source/engine3d/svx3ditems.cxx | 266 + svx/source/engine3d/view3d.cxx | 1599 ++++ svx/source/engine3d/view3d1.cxx | 177 + svx/source/engine3d/viewpt3d2.cxx | 153 + svx/source/fmcomp/dbaexchange.cxx | 628 ++ svx/source/fmcomp/dbaobjectex.cxx | 133 + svx/source/fmcomp/fmgridcl.cxx | 2061 +++++ svx/source/fmcomp/fmgridif.cxx | 2764 +++++++ svx/source/fmcomp/gridcell.cxx | 4634 +++++++++++ svx/source/fmcomp/gridcols.cxx | 103 + svx/source/fmcomp/gridctrl.cxx | 3645 +++++++++ svx/source/fmcomp/xmlexchg.cxx | 61 + svx/source/form/ParseContext.cxx | 200 + svx/source/form/dataaccessdescriptor.cxx | 356 + svx/source/form/databaselocationinput.cxx | 249 + svx/source/form/datalistener.cxx | 91 + svx/source/form/datanavi.cxx | 3229 ++++++++ svx/source/form/dbcharsethelper.cxx | 48 + svx/source/form/delayedevent.cxx | 48 + svx/source/form/filtnav.cxx | 1926 +++++ svx/source/form/fmPropBrw.cxx | 580 ++ svx/source/form/fmcontrolbordermanager.cxx | 425 + svx/source/form/fmcontrollayout.cxx | 313 + svx/source/form/fmdmod.cxx | 90 + svx/source/form/fmdocumentclassification.cxx | 196 + svx/source/form/fmdpage.cxx | 115 + svx/source/form/fmexch.cxx | 386 + svx/source/form/fmexpl.cxx | 554 ++ svx/source/form/fmmodel.cxx | 208 + svx/source/form/fmobj.cxx | 670 ++ svx/source/form/fmobjfac.cxx | 231 + svx/source/form/fmpage.cxx | 170 + svx/source/form/fmpgeimp.cxx | 713 ++ svx/source/form/fmscriptingenv.cxx | 1040 +++ svx/source/form/fmservs.cxx | 74 + svx/source/form/fmshell.cxx | 1417 ++++ svx/source/form/fmshimp.cxx | 3972 +++++++++ svx/source/form/fmsrccfg.cxx | 286 + svx/source/form/fmsrcimp.cxx | 1063 +++ svx/source/form/fmtextcontroldialogs.cxx | 79 + svx/source/form/fmtextcontrolfeature.cxx | 118 + svx/source/form/fmtextcontrolshell.cxx | 1316 +++ svx/source/form/fmtools.cxx | 384 + svx/source/form/fmundo.cxx | 1265 +++ svx/source/form/fmview.cxx | 570 ++ svx/source/form/fmvwimp.cxx | 1917 +++++ svx/source/form/formcontrolfactory.cxx | 713 ++ svx/source/form/formcontroller.cxx | 4194 ++++++++++ svx/source/form/formcontrolling.cxx | 496 ++ svx/source/form/formdispatchinterceptor.cxx | 177 + svx/source/form/formfeaturedispatcher.cxx | 191 + svx/source/form/formtoolbars.cxx | 93 + svx/source/form/labelitemwindow.cxx | 43 + svx/source/form/legacyformcontroller.cxx | 201 + svx/source/form/navigatortree.cxx | 2135 +++++ svx/source/form/navigatortreemodel.cxx | 908 +++ svx/source/form/sdbdatacolumn.cxx | 55 + svx/source/form/sqlparserclient.cxx | 50 + svx/source/form/tabwin.cxx | 304 + svx/source/form/tbxform.cxx | 257 + svx/source/form/typemap.cxx | 52 + svx/source/form/xfm_addcondition.cxx | 157 + svx/source/gallery2/GalleryControl.cxx | 62 + svx/source/gallery2/codec.cxx | 152 + svx/source/gallery2/codec.hxx | 42 + svx/source/gallery2/galbrws1.cxx | 487 ++ svx/source/gallery2/galbrws1.hxx | 89 + svx/source/gallery2/galbrws2.cxx | 1249 +++ svx/source/gallery2/galctrl.cxx | 407 + svx/source/gallery2/galexpl.cxx | 296 + svx/source/gallery2/galini.cxx | 94 + svx/source/gallery2/gallery1.cxx | 769 ++ svx/source/gallery2/gallerydrawmodel.hxx | 39 + svx/source/gallery2/galmisc.cxx | 553 ++ svx/source/gallery2/galobj.cxx | 481 ++ svx/source/gallery2/galtheme.cxx | 1468 ++++ svx/source/gengal/gengal.cxx | 323 + svx/source/gengal/gengal.sh | 95 + svx/source/inc/AccessibleFrameSelector.hxx | 137 + svx/source/inc/DefaultShapesPanel.hxx | 83 + svx/source/inc/GraphCtlAccessibleContext.hxx | 190 + svx/source/inc/ShapesUtil.hxx | 39 + svx/source/inc/cell.hxx | 221 + svx/source/inc/celltypes.hxx | 97 + svx/source/inc/charmapacc.hxx | 223 + svx/source/inc/clonelist.hxx | 47 + svx/source/inc/datalistener.hxx | 73 + svx/source/inc/datanavi.hxx | 616 ++ svx/source/inc/delayedevent.hxx | 81 + svx/source/inc/docrecovery.hxx | 503 ++ svx/source/inc/filtnav.hxx | 339 + svx/source/inc/findtextfield.hxx | 70 + svx/source/inc/fmPropBrw.hxx | 104 + svx/source/inc/fmcontrolbordermanager.hxx | 230 + svx/source/inc/fmcontrollayout.hxx | 67 + svx/source/inc/fmdocumentclassification.hxx | 71 + svx/source/inc/fmexch.hxx | 252 + svx/source/inc/fmexpl.hxx | 550 ++ svx/source/inc/fmobj.hxx | 119 + svx/source/inc/fmpgeimp.hxx | 144 + svx/source/inc/fmprop.hxx | 151 + svx/source/inc/fmscriptingenv.hxx | 97 + svx/source/inc/fmservs.hxx | 110 + svx/source/inc/fmshimp.hxx | 557 ++ svx/source/inc/fmslotinvalidator.hxx | 33 + svx/source/inc/fmtextcontroldialogs.hxx | 50 + svx/source/inc/fmtextcontrolfeature.hxx | 93 + svx/source/inc/fmtextcontrolshell.hxx | 202 + svx/source/inc/fmundo.hxx | 199 + svx/source/inc/fmurl.hxx | 53 + svx/source/inc/fmvwimp.hxx | 302 + svx/source/inc/formcontrolfactory.hxx | 109 + svx/source/inc/formcontroller.hxx | 565 ++ svx/source/inc/formcontrolling.hxx | 215 + svx/source/inc/formdispatchinterceptor.hxx | 107 + svx/source/inc/formfeaturedispatcher.hxx | 111 + svx/source/inc/formtoolbars.hxx | 62 + svx/source/inc/frmselimpl.hxx | 285 + svx/source/inc/gridcell.hxx | 1101 +++ svx/source/inc/gridcols.hxx | 54 + svx/source/inc/sdbdatacolumn.hxx | 59 + svx/source/inc/sqlparserclient.hxx | 70 + svx/source/inc/svdobjplusdata.hxx | 46 + svx/source/inc/svdobjuserdatalist.hxx | 37 + svx/source/inc/svdoutlinercache.hxx | 51 + svx/source/inc/svdpdf.hxx | 148 + svx/source/inc/svxpixelctlaccessiblecontext.hxx | 154 + svx/source/inc/svxrectctaccessiblecontext.hxx | 233 + svx/source/inc/tablemodel.hxx | 209 + svx/source/inc/tabwin.hxx | 93 + svx/source/inc/tbxform.hxx | 120 + svx/source/inc/treevisitor.hxx | 104 + svx/source/inc/xfm_addcondition.hxx | 76 + svx/source/inc/xmlxtexp.hxx | 64 + svx/source/inc/xmlxtimp.hxx | 56 + svx/source/items/SmartTagItem.cxx | 96 + svx/source/items/algitem.cxx | 313 + svx/source/items/autoformathelper.cxx | 423 + svx/source/items/chrtitem.cxx | 177 + svx/source/items/clipfmtitem.cxx | 149 + svx/source/items/customshapeitem.cxx | 296 + svx/source/items/drawitem.cxx | 349 + svx/source/items/e3ditem.cxx | 101 + svx/source/items/galleryitem.cxx | 140 + svx/source/items/grfitem.cxx | 122 + svx/source/items/hlnkitem.cxx | 184 + svx/source/items/legacyitem.cxx | 105 + svx/source/items/numfmtsh.cxx | 1568 ++++ svx/source/items/numinf.cxx | 131 + svx/source/items/ofaitem.cxx | 40 + svx/source/items/pageitem.cxx | 289 + svx/source/items/postattr.cxx | 155 + svx/source/items/rotmodit.cxx | 125 + svx/source/items/svxerr.cxx | 43 + svx/source/items/viewlayoutitem.cxx | 167 + svx/source/items/zoomslideritem.cxx | 218 + svx/source/mnuctrls/clipboardctl.cxx | 133 + svx/source/mnuctrls/smarttagmenu.cxx | 242 + svx/source/sdr/animation/animationstate.cxx | 135 + svx/source/sdr/animation/objectanimator.cxx | 36 + svx/source/sdr/animation/scheduler.cxx | 172 + .../sdr/attribute/sdrallfillattributeshelper.cxx | 257 + .../sdr/attribute/sdreffectstextattribute.cxx | 78 + svx/source/sdr/attribute/sdrfilltextattribute.cxx | 68 + svx/source/sdr/attribute/sdrformtextattribute.cxx | 375 + .../sdr/attribute/sdrformtextoutlineattribute.cxx | 141 + .../sdr/attribute/sdrlineeffectstextattribute.cxx | 78 + .../attribute/sdrlinefilleffectstextattribute.cxx | 80 + svx/source/sdr/attribute/sdrtextattribute.cxx | 422 + svx/source/sdr/contact/displayinfo.cxx | 88 + svx/source/sdr/contact/objectcontact.cxx | 215 + .../sdr/contact/objectcontactofobjlistpainter.cxx | 189 + svx/source/sdr/contact/objectcontactofpageview.cxx | 440 + svx/source/sdr/contact/sdrmediawindow.cxx | 174 + svx/source/sdr/contact/sdrmediawindow.hxx | 60 + svx/source/sdr/contact/viewcontact.cxx | 288 + svx/source/sdr/contact/viewcontactofe3d.cxx | 195 + svx/source/sdr/contact/viewcontactofe3dcube.cxx | 89 + svx/source/sdr/contact/viewcontactofe3dextrude.cxx | 84 + svx/source/sdr/contact/viewcontactofe3dlathe.cxx | 97 + svx/source/sdr/contact/viewcontactofe3dpolygon.cxx | 170 + svx/source/sdr/contact/viewcontactofe3dscene.cxx | 454 ++ svx/source/sdr/contact/viewcontactofe3dsphere.cxx | 81 + svx/source/sdr/contact/viewcontactofgraphic.cxx | 412 + svx/source/sdr/contact/viewcontactofgroup.cxx | 83 + .../contact/viewcontactofmasterpagedescriptor.cxx | 102 + svx/source/sdr/contact/viewcontactofpageobj.cxx | 79 + .../sdr/contact/viewcontactofsdrcaptionobj.cxx | 196 + svx/source/sdr/contact/viewcontactofsdrcircobj.cxx | 102 + svx/source/sdr/contact/viewcontactofsdredgeobj.cxx | 65 + .../sdr/contact/viewcontactofsdrmeasureobj.cxx | 127 + .../sdr/contact/viewcontactofsdrmediaobj.cxx | 129 + svx/source/sdr/contact/viewcontactofsdrobj.cxx | 190 + .../sdr/contact/viewcontactofsdrobjcustomshape.cxx | 243 + svx/source/sdr/contact/viewcontactofsdrole2obj.cxx | 207 + svx/source/sdr/contact/viewcontactofsdrpage.cxx | 624 ++ svx/source/sdr/contact/viewcontactofsdrpathobj.cxx | 206 + svx/source/sdr/contact/viewcontactofsdrrectobj.cxx | 88 + svx/source/sdr/contact/viewcontactoftextobj.cxx | 36 + svx/source/sdr/contact/viewcontactofunocontrol.cxx | 132 + svx/source/sdr/contact/viewcontactofvirtobj.cxx | 100 + svx/source/sdr/contact/viewobjectcontact.cxx | 474 ++ svx/source/sdr/contact/viewobjectcontactofe3d.cxx | 86 + .../sdr/contact/viewobjectcontactofe3dscene.cxx | 137 + .../sdr/contact/viewobjectcontactofgraphic.cxx | 62 + .../sdr/contact/viewobjectcontactofgroup.cxx | 106 + .../viewobjectcontactofmasterpagedescriptor.cxx | 131 + .../sdr/contact/viewobjectcontactofpageobj.cxx | 319 + .../sdr/contact/viewobjectcontactofsdrmediaobj.cxx | 158 + .../sdr/contact/viewobjectcontactofsdrobj.cxx | 193 + .../sdr/contact/viewobjectcontactofsdrole2obj.cxx | 150 + .../sdr/contact/viewobjectcontactofsdrpage.cxx | 633 ++ .../sdr/contact/viewobjectcontactofunocontrol.cxx | 1786 ++++ .../sdr/contact/viewobjectcontactredirector.cxx | 44 + svx/source/sdr/misc/ImageMapInfo.cxx | 120 + svx/source/sdr/overlay/overlayanimatedbitmapex.cxx | 113 + svx/source/sdr/overlay/overlaybitmapex.cxx | 72 + svx/source/sdr/overlay/overlaycrosshair.cxx | 67 + svx/source/sdr/overlay/overlayhandle.cxx | 55 + svx/source/sdr/overlay/overlayhelpline.cxx | 74 + svx/source/sdr/overlay/overlayline.cxx | 74 + svx/source/sdr/overlay/overlaymanager.cxx | 349 + svx/source/sdr/overlay/overlaymanagerbuffered.cxx | 440 + svx/source/sdr/overlay/overlayobject.cxx | 229 + svx/source/sdr/overlay/overlayobjectcell.cxx | 81 + svx/source/sdr/overlay/overlayobjectlist.cxx | 144 + svx/source/sdr/overlay/overlaypolypolygon.cxx | 83 + .../overlay/overlayprimitive2dsequenceobject.cxx | 42 + svx/source/sdr/overlay/overlayrectangle.cxx | 113 + svx/source/sdr/overlay/overlayrollingrectangle.cxx | 117 + svx/source/sdr/overlay/overlayselection.cxx | 223 + svx/source/sdr/overlay/overlaytools.cxx | 589 ++ svx/source/sdr/overlay/overlaytriangle.cxx | 61 + svx/source/sdr/primitive2d/primitivefactory2d.cxx | 113 + svx/source/sdr/primitive2d/sdrattributecreator.cxx | 1129 +++ .../sdr/primitive2d/sdrcaptionprimitive2d.cxx | 166 + .../sdr/primitive2d/sdrconnectorprimitive2d.cxx | 105 + .../sdr/primitive2d/sdrcustomshapeprimitive2d.cxx | 130 + .../sdr/primitive2d/sdrdecompositiontools.cxx | 574 ++ .../sdr/primitive2d/sdrellipseprimitive2d.cxx | 261 + .../sdr/primitive2d/sdrframeborderprimitive2d.cxx | 934 +++ svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx | 180 + .../sdr/primitive2d/sdrmeasureprimitive2d.cxx | 495 ++ svx/source/sdr/primitive2d/sdrole2primitive2d.cxx | 174 + .../sdr/primitive2d/sdrolecontentprimitive2d.cxx | 177 + svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx | 154 + svx/source/sdr/primitive2d/sdrprimitivetools.cxx | 64 + .../sdr/primitive2d/sdrrectangleprimitive2d.cxx | 150 + svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx | 529 ++ .../sdr/primitive3d/sdrattributecreator3d.cxx | 145 + svx/source/sdr/properties/attributeproperties.cxx | 526 ++ svx/source/sdr/properties/captionproperties.cxx | 99 + svx/source/sdr/properties/circleproperties.cxx | 123 + svx/source/sdr/properties/connectorproperties.cxx | 87 + .../sdr/properties/customshapeproperties.cxx | 231 + svx/source/sdr/properties/defaultproperties.cxx | 254 + .../sdr/properties/e3dcompoundproperties.cxx | 144 + svx/source/sdr/properties/e3dextrudeproperties.cxx | 74 + svx/source/sdr/properties/e3dlatheproperties.cxx | 84 + svx/source/sdr/properties/e3dproperties.cxx | 75 + svx/source/sdr/properties/e3dsceneproperties.cxx | 292 + svx/source/sdr/properties/e3dsphereproperties.cxx | 69 + svx/source/sdr/properties/emptyproperties.cxx | 118 + svx/source/sdr/properties/graphicproperties.cxx | 148 + svx/source/sdr/properties/groupproperties.cxx | 275 + svx/source/sdr/properties/itemsettools.cxx | 86 + svx/source/sdr/properties/measureproperties.cxx | 128 + svx/source/sdr/properties/oleproperties.cxx | 73 + svx/source/sdr/properties/pageproperties.cxx | 99 + svx/source/sdr/properties/properties.cxx | 192 + svx/source/sdr/properties/rectangleproperties.cxx | 68 + svx/source/sdr/properties/textproperties.cxx | 611 ++ .../sidebar/ContextChangeEventMultiplexer.cxx | 90 + svx/source/sidebar/EmptyPanel.cxx | 43 + svx/source/sidebar/EmptyPanel.hxx | 45 + svx/source/sidebar/PanelFactory.cxx | 220 + svx/source/sidebar/SelectionAnalyzer.cxx | 479 ++ svx/source/sidebar/SelectionChangeHandler.cxx | 101 + svx/source/sidebar/area/AreaPropertyPanel.cxx | 149 + svx/source/sidebar/area/AreaPropertyPanel.hxx | 93 + svx/source/sidebar/area/AreaPropertyPanelBase.cxx | 1441 ++++ .../sidebar/area/AreaTransparencyGradientPopup.cxx | 181 + svx/source/sidebar/glow/GlowPropertyPanel.cxx | 162 + svx/source/sidebar/glow/GlowPropertyPanel.hxx | 64 + .../sidebar/graphic/GraphicPropertyPanel.cxx | 415 + .../sidebar/graphic/GraphicPropertyPanel.hxx | 99 + .../sidebar/inspector/InspectorTextPanel.cxx | 77 + .../sidebar/inspector/InspectorTextPanel.hxx | 55 + svx/source/sidebar/line/LinePropertyPanel.cxx | 172 + svx/source/sidebar/line/LinePropertyPanel.hxx | 100 + svx/source/sidebar/line/LinePropertyPanelBase.cxx | 484 ++ svx/source/sidebar/line/LineWidthPopup.cxx | 226 + svx/source/sidebar/line/LineWidthValueSet.cxx | 172 + svx/source/sidebar/line/LineWidthValueSet.hxx | 55 + svx/source/sidebar/lists/ListsPropertyPanel.cxx | 64 + svx/source/sidebar/lists/ListsPropertyPanel.hxx | 53 + svx/source/sidebar/media/MediaPlaybackPanel.cxx | 190 + svx/source/sidebar/media/MediaPlaybackPanel.hxx | 83 + svx/source/sidebar/nbdtmg.cxx | 913 +++ svx/source/sidebar/nbdtmgfact.cxx | 43 + .../sidebar/paragraph/ParaLineSpacingControl.cxx | 414 + .../sidebar/paragraph/ParaLineSpacingControl.hxx | 79 + .../sidebar/paragraph/ParaLineSpacingPopup.cxx | 98 + svx/source/sidebar/paragraph/ParaPropertyPanel.cxx | 509 ++ svx/source/sidebar/paragraph/ParaPropertyPanel.hxx | 137 + .../sidebar/paragraph/ParaSpacingControl.cxx | 257 + svx/source/sidebar/paragraph/ParaSpacingWindow.cxx | 368 + svx/source/sidebar/paragraph/ParaSpacingWindow.hxx | 115 + .../sidebar/possize/PosSizePropertyPanel.cxx | 1088 +++ .../sidebar/possize/PosSizePropertyPanel.hxx | 197 + svx/source/sidebar/shadow/ShadowPropertyPanel.cxx | 334 + svx/source/sidebar/shadow/ShadowPropertyPanel.hxx | 92 + svx/source/sidebar/shapes/DefaultShapesPanel.cxx | 160 + svx/source/sidebar/shapes/ShapesUtil.cxx | 212 + .../sidebar/softedge/SoftEdgePropertyPanel.cxx | 96 + .../sidebar/softedge/SoftEdgePropertyPanel.hxx | 56 + svx/source/sidebar/styles/StylesPropertyPanel.cxx | 53 + svx/source/sidebar/styles/StylesPropertyPanel.hxx | 34 + .../sidebar/text/TextCharacterSpacingControl.cxx | 198 + .../sidebar/text/TextCharacterSpacingControl.hxx | 69 + .../sidebar/text/TextCharacterSpacingPopup.cxx | 83 + svx/source/sidebar/text/TextPropertyPanel.cxx | 162 + svx/source/sidebar/text/TextPropertyPanel.hxx | 79 + svx/source/sidebar/text/TextUnderlineControl.cxx | 137 + svx/source/sidebar/text/TextUnderlineControl.hxx | 60 + svx/source/sidebar/text/TextUnderlinePopup.cxx | 83 + .../sidebar/tools/ValueSetWithTextControl.cxx | 121 + svx/source/smarttags/SmartTagMgr.cxx | 527 ++ svx/source/stbctrls/insctrl.cxx | 83 + svx/source/stbctrls/modctrl.cxx | 160 + svx/source/stbctrls/modctrl_internal.hxx | 30 + svx/source/stbctrls/pszctrl.cxx | 480 ++ svx/source/stbctrls/selctrl.cxx | 164 + svx/source/stbctrls/stbctrls.h | 35 + svx/source/stbctrls/xmlsecctrl.cxx | 160 + svx/source/stbctrls/zoomctrl.cxx | 228 + svx/source/stbctrls/zoomsliderctrl.cxx | 398 + svx/source/styles/ColorSets.cxx | 107 + svx/source/styles/CommonStyleManager.cxx | 26 + svx/source/styles/CommonStylePreviewRenderer.cxx | 228 + svx/source/svdraw/ActionDescriptionProvider.cxx | 66 + svx/source/svdraw/charthelper.cxx | 138 + svx/source/svdraw/clonelist.cxx | 127 + svx/source/svdraw/gradtrns.cxx | 527 ++ svx/source/svdraw/gradtrns.hxx | 55 + svx/source/svdraw/polypolygoneditor.cxx | 182 + .../svdraw/presetooxhandleadjustmentrelations.cxx | 336 + .../svdraw/presetooxhandleadjustmentrelations.hxx | 29 + svx/source/svdraw/sdrhittesthelper.cxx | 175 + svx/source/svdraw/sdrmasterpagedescriptor.cxx | 104 + svx/source/svdraw/sdrpagewindow.cxx | 519 ++ svx/source/svdraw/sdrpaintwindow.cxx | 343 + svx/source/svdraw/sdrundomanager.cxx | 149 + svx/source/svdraw/selectioncontroller.cxx | 120 + svx/source/svdraw/svdattr.cxx | 1982 +++++ svx/source/svdraw/svdcrtv.cxx | 921 +++ svx/source/svdraw/svddrag.cxx | 129 + svx/source/svdraw/svddrgm1.hxx | 232 + svx/source/svdraw/svddrgmt.cxx | 3862 +++++++++ svx/source/svdraw/svddrgv.cxx | 925 +++ svx/source/svdraw/svdedtv.cxx | 1046 +++ svx/source/svdraw/svdedtv1.cxx | 1990 +++++ svx/source/svdraw/svdedtv2.cxx | 2198 +++++ svx/source/svdraw/svdedxv.cxx | 2833 +++++++ svx/source/svdraw/svdetc.cxx | 748 ++ svx/source/svdraw/svdfmtf.cxx | 1649 ++++ svx/source/svdraw/svdfmtf.hxx | 173 + svx/source/svdraw/svdglev.cxx | 399 + svx/source/svdraw/svdglue.cxx | 389 + svx/source/svdraw/svdhdl.cxx | 2680 ++++++ svx/source/svdraw/svdhlpln.cxx | 109 + svx/source/svdraw/svditer.cxx | 143 + svx/source/svdraw/svdlayer.cxx | 361 + svx/source/svdraw/svdmark.cxx | 790 ++ svx/source/svdraw/svdmodel.cxx | 2035 +++++ svx/source/svdraw/svdmrkv.cxx | 2479 ++++++ svx/source/svdraw/svdmrkv1.cxx | 545 ++ svx/source/svdraw/svdoashp.cxx | 3241 ++++++++ svx/source/svdraw/svdoattr.cxx | 99 + svx/source/svdraw/svdobj.cxx | 3213 ++++++++ svx/source/svdraw/svdobjplusdata.cxx | 61 + svx/source/svdraw/svdobjuserdatalist.cxx | 36 + svx/source/svdraw/svdocapt.cxx | 768 ++ svx/source/svdraw/svdocirc.cxx | 1159 +++ svx/source/svdraw/svdoedge.cxx | 2625 ++++++ svx/source/svdraw/svdograf.cxx | 1257 +++ svx/source/svdraw/svdogrp.cxx | 791 ++ svx/source/svdraw/svdomeas.cxx | 1436 ++++ svx/source/svdraw/svdomedia.cxx | 402 + svx/source/svdraw/svdoole2.cxx | 1946 +++++ svx/source/svdraw/svdopage.cxx | 183 + svx/source/svdraw/svdopath.cxx | 2982 +++++++ svx/source/svdraw/svdorect.cxx | 583 ++ svx/source/svdraw/svdotext.cxx | 2157 +++++ svx/source/svdraw/svdotextdecomposition.cxx | 1680 ++++ svx/source/svdraw/svdotextpathdecomposition.cxx | 785 ++ svx/source/svdraw/svdotxat.cxx | 455 ++ svx/source/svdraw/svdotxdr.cxx | 248 + svx/source/svdraw/svdotxed.cxx | 360 + svx/source/svdraw/svdotxfl.cxx | 28 + svx/source/svdraw/svdotxln.cxx | 277 + svx/source/svdraw/svdotxtr.cxx | 502 ++ svx/source/svdraw/svdouno.cxx | 510 ++ svx/source/svdraw/svdoutl.cxx | 106 + svx/source/svdraw/svdoutlinercache.cxx | 98 + svx/source/svdraw/svdovirt.cxx | 549 ++ svx/source/svdraw/svdpage.cxx | 1789 ++++ svx/source/svdraw/svdpagv.cxx | 881 ++ svx/source/svdraw/svdpdf.cxx | 1151 +++ svx/source/svdraw/svdpntv.cxx | 1208 +++ svx/source/svdraw/svdpoev.cxx | 652 ++ svx/source/svdraw/svdsnpv.cxx | 633 ++ svx/source/svdraw/svdtext.cxx | 146 + svx/source/svdraw/svdtrans.cxx | 926 +++ svx/source/svdraw/svdundo.cxx | 1751 ++++ svx/source/svdraw/svdview.cxx | 1460 ++++ svx/source/svdraw/svdviter.cxx | 171 + svx/source/svdraw/svdxcgv.cxx | 767 ++ svx/source/svdraw/textchain.cxx | 128 + svx/source/svdraw/textchaincursor.cxx | 203 + svx/source/svdraw/textchainflow.cxx | 315 + svx/source/table/accessiblecell.cxx | 609 ++ svx/source/table/accessiblecell.hxx | 132 + svx/source/table/accessibletableshape.cxx | 1323 +++ svx/source/table/cell.cxx | 1701 ++++ svx/source/table/cellcursor.cxx | 545 ++ svx/source/table/cellcursor.hxx | 71 + svx/source/table/cellrange.cxx | 116 + svx/source/table/cellrange.hxx | 61 + svx/source/table/propertyset.cxx | 206 + svx/source/table/propertyset.hxx | 96 + svx/source/table/svdotable.cxx | 2531 ++++++ svx/source/table/tablecolumn.cxx | 289 + svx/source/table/tablecolumn.hxx | 83 + svx/source/table/tablecolumns.cxx | 121 + svx/source/table/tablecolumns.hxx | 61 + svx/source/table/tablecontroller.cxx | 3263 ++++++++ svx/source/table/tabledesign.cxx | 724 ++ svx/source/table/tablehandles.cxx | 312 + svx/source/table/tablehandles.hxx | 89 + svx/source/table/tablelayouter.cxx | 1335 +++ svx/source/table/tablelayouter.hxx | 171 + svx/source/table/tablemodel.cxx | 1117 +++ svx/source/table/tablerow.cxx | 351 + svx/source/table/tablerow.hxx | 84 + svx/source/table/tablerows.cxx | 114 + svx/source/table/tablerows.hxx | 61 + svx/source/table/tablertfexporter.cxx | 244 + svx/source/table/tablertfimporter.cxx | 507 ++ svx/source/table/tableundo.cxx | 518 ++ svx/source/table/tableundo.hxx | 259 + svx/source/table/viewcontactoftableobj.cxx | 417 + svx/source/table/viewcontactoftableobj.hxx | 47 + svx/source/tbxctrls/Palette.cxx | 364 + svx/source/tbxctrls/PaletteManager.cxx | 353 + svx/source/tbxctrls/SvxColorChildWindow.cxx | 43 + svx/source/tbxctrls/SvxColorValueSet.cxx | 169 + svx/source/tbxctrls/SvxPresetListBox.cxx | 110 + svx/source/tbxctrls/bulletsnumbering.cxx | 242 + svx/source/tbxctrls/colrctrl.cxx | 427 + svx/source/tbxctrls/extrusioncontrols.cxx | 936 +++ svx/source/tbxctrls/extrusioncontrols.hxx | 220 + svx/source/tbxctrls/fillctrl.cxx | 979 +++ svx/source/tbxctrls/fontworkgallery.cxx | 731 ++ svx/source/tbxctrls/formatpaintbrushctrl.cxx | 105 + svx/source/tbxctrls/grafctrl.cxx | 977 +++ svx/source/tbxctrls/itemwin.cxx | 351 + svx/source/tbxctrls/layctrl.cxx | 803 ++ svx/source/tbxctrls/lboxctrl.cxx | 223 + svx/source/tbxctrls/linectrl.cxx | 635 ++ svx/source/tbxctrls/linemetricbox.hxx | 58 + svx/source/tbxctrls/linewidthctrl.cxx | 101 + svx/source/tbxctrls/tbcontrl.cxx | 4039 +++++++++ svx/source/tbxctrls/tbunocontroller.cxx | 550 ++ svx/source/tbxctrls/tbunosearchcontrollers.cxx | 1662 ++++ svx/source/tbxctrls/tbxcolor.cxx | 95 + svx/source/tbxctrls/tbxcolorupdate.cxx | 338 + svx/source/tbxctrls/tbxdrctl.cxx | 99 + svx/source/tbxctrls/verttexttbxctrl.cxx | 163 + svx/source/toolbars/extrusionbar.cxx | 1319 +++ svx/source/toolbars/fontworkbar.cxx | 589 ++ svx/source/uitest/sdrobject.cxx | 164 + svx/source/uitest/uiobject.cxx | 62 + .../chinese_dictionarydialog.cxx | 675 ++ .../chinese_dictionarydialog.hxx | 168 + .../chinese_translation_unodialog.cxx | 229 + .../chinese_translation_unodialog.hxx | 125 + .../chinese_translationdialog.cxx | 97 + .../chinese_translationdialog.hxx | 53 + .../unodialogs/textconversiondlgs/services.cxx | 49 + svx/source/unodraw/UnoGraphicExporter.cxx | 1306 +++ svx/source/unodraw/UnoGraphicExporter.hxx | 33 + svx/source/unodraw/UnoNameItemTable.cxx | 260 + svx/source/unodraw/UnoNameItemTable.hxx | 84 + svx/source/unodraw/UnoNamespaceMap.cxx | 275 + svx/source/unodraw/XPropertyTable.cxx | 669 ++ svx/source/unodraw/gluepts.cxx | 513 ++ svx/source/unodraw/gluepts.hxx | 35 + svx/source/unodraw/recoveryui.cxx | 331 + svx/source/unodraw/shapeimpl.hxx | 108 + svx/source/unodraw/shapepropertynotifier.cxx | 170 + svx/source/unodraw/tableshape.cxx | 177 + svx/source/unodraw/unobrushitemhelper.cxx | 340 + svx/source/unodraw/unobtabl.cxx | 102 + svx/source/unodraw/unoctabl.cxx | 181 + svx/source/unodraw/unodtabl.cxx | 88 + svx/source/unodraw/unogtabl.cxx | 88 + svx/source/unodraw/unohtabl.cxx | 86 + svx/source/unodraw/unomlstr.cxx | 60 + svx/source/unodraw/unomod.cxx | 681 ++ svx/source/unodraw/unomtabl.cxx | 413 + svx/source/unodraw/unopage.cxx | 903 +++ svx/source/unodraw/unopool.cxx | 374 + svx/source/unodraw/unoprov.cxx | 2047 +++++ svx/source/unodraw/unoshap2.cxx | 1794 ++++ svx/source/unodraw/unoshap3.cxx | 1035 +++ svx/source/unodraw/unoshap4.cxx | 1013 +++ svx/source/unodraw/unoshape.cxx | 4011 +++++++++ svx/source/unodraw/unoshcol.cxx | 259 + svx/source/unodraw/unoshtxt.cxx | 1017 +++ svx/source/unodraw/unottabl.cxx | 87 + svx/source/unogallery/unogalitem.cxx | 370 + svx/source/unogallery/unogalitem.hxx | 104 + svx/source/unogallery/unogaltheme.cxx | 362 + svx/source/unogallery/unogaltheme.hxx | 100 + svx/source/unogallery/unogalthemeprovider.cxx | 246 + svx/source/xml/xmleohlp.cxx | 716 ++ svx/source/xml/xmlexport.cxx | 249 + svx/source/xml/xmlgrhlp.cxx | 1120 +++ svx/source/xml/xmlxtexp.cxx | 485 ++ svx/source/xml/xmlxtimp.cxx | 474 ++ svx/source/xoutdev/XPropertyEntry.cxx | 32 + svx/source/xoutdev/_xoutbmp.cxx | 399 + svx/source/xoutdev/_xpoly.cxx | 948 +++ svx/source/xoutdev/xattr.cxx | 3037 +++++++ svx/source/xoutdev/xattr2.cxx | 696 ++ svx/source/xoutdev/xattrbmp.cxx | 342 + svx/source/xoutdev/xpool.cxx | 225 + svx/source/xoutdev/xtabbtmp.cxx | 115 + svx/source/xoutdev/xtabcolr.cxx | 174 + svx/source/xoutdev/xtabdash.cxx | 223 + svx/source/xoutdev/xtabgrdt.cxx | 222 + svx/source/xoutdev/xtabhtch.cxx | 197 + svx/source/xoutdev/xtable.cxx | 392 + svx/source/xoutdev/xtablend.cxx | 166 + svx/source/xoutdev/xtabptrn.cxx | 150 + 676 files changed, 318660 insertions(+) create mode 100644 svx/source/accessibility/AccessibleControlShape.cxx create mode 100644 svx/source/accessibility/AccessibleEmptyEditSource.cxx create mode 100644 svx/source/accessibility/AccessibleEmptyEditSource.hxx create mode 100644 svx/source/accessibility/AccessibleFrameSelector.cxx create mode 100644 svx/source/accessibility/AccessibleGraphicShape.cxx create mode 100644 svx/source/accessibility/AccessibleOLEShape.cxx create mode 100644 svx/source/accessibility/AccessibleShape.cxx create mode 100644 svx/source/accessibility/AccessibleShapeInfo.cxx create mode 100644 svx/source/accessibility/AccessibleShapeTreeInfo.cxx create mode 100644 svx/source/accessibility/AccessibleTextEventQueue.cxx create mode 100644 svx/source/accessibility/AccessibleTextEventQueue.hxx create mode 100644 svx/source/accessibility/AccessibleTextHelper.cxx create mode 100644 svx/source/accessibility/ChildrenManager.cxx create mode 100644 svx/source/accessibility/ChildrenManagerImpl.cxx create mode 100644 svx/source/accessibility/ChildrenManagerImpl.hxx create mode 100644 svx/source/accessibility/DescriptionGenerator.cxx create mode 100644 svx/source/accessibility/GraphCtlAccessibleContext.cxx create mode 100644 svx/source/accessibility/ShapeTypeHandler.cxx create mode 100644 svx/source/accessibility/SvxShapeTypes.cxx create mode 100644 svx/source/accessibility/charmapacc.cxx create mode 100644 svx/source/accessibility/lookupcolorname.cxx create mode 100644 svx/source/accessibility/lookupcolorname.hxx create mode 100644 svx/source/accessibility/svxpixelctlaccessiblecontext.cxx create mode 100644 svx/source/accessibility/svxrectctaccessiblecontext.cxx create mode 100644 svx/source/core/extedit.cxx create mode 100644 svx/source/core/graphichelper.cxx create mode 100644 svx/source/customshapes/EnhancedCustomShape2d.cxx create mode 100644 svx/source/customshapes/EnhancedCustomShape3d.cxx create mode 100644 svx/source/customshapes/EnhancedCustomShape3d.hxx create mode 100644 svx/source/customshapes/EnhancedCustomShapeEngine.cxx create mode 100644 svx/source/customshapes/EnhancedCustomShapeFontWork.cxx create mode 100644 svx/source/customshapes/EnhancedCustomShapeFontWork.hxx create mode 100644 svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx create mode 100644 svx/source/customshapes/EnhancedCustomShapeGeometry.cxx create mode 100644 svx/source/customshapes/EnhancedCustomShapeHandle.cxx create mode 100644 svx/source/customshapes/EnhancedCustomShapeHandle.hxx create mode 100644 svx/source/customshapes/EnhancedCustomShapeTypeNames.cxx create mode 100644 svx/source/dialog/AccessibilityCheckDialog.cxx create mode 100644 svx/source/dialog/ClassificationCommon.cxx create mode 100644 svx/source/dialog/ClassificationDialog.cxx create mode 100644 svx/source/dialog/ClassificationEditView.cxx create mode 100644 svx/source/dialog/ClassificationEditView.hxx create mode 100644 svx/source/dialog/SafeModeDialog.cxx create mode 100644 svx/source/dialog/SafeModeDialog.hxx create mode 100644 svx/source/dialog/SafeModeUI.cxx create mode 100644 svx/source/dialog/SpellDialogChildWindow.cxx create mode 100644 svx/source/dialog/SvxNumOptionsTabPageHelper.cxx create mode 100644 svx/source/dialog/_bmpmask.cxx create mode 100644 svx/source/dialog/_contdlg.cxx create mode 100644 svx/source/dialog/charmap.cxx create mode 100644 svx/source/dialog/compressgraphicdialog.cxx create mode 100644 svx/source/dialog/connctrl.cxx create mode 100644 svx/source/dialog/contimp.hxx create mode 100644 svx/source/dialog/contwnd.cxx create mode 100644 svx/source/dialog/contwnd.hxx create mode 100644 svx/source/dialog/crashreportdlg.cxx create mode 100644 svx/source/dialog/crashreportdlg.hxx create mode 100644 svx/source/dialog/crashreportui.cxx create mode 100644 svx/source/dialog/ctredlin.cxx create mode 100644 svx/source/dialog/databaseregistrationui.cxx create mode 100644 svx/source/dialog/dialcontrol.cxx create mode 100644 svx/source/dialog/dialmgr.cxx create mode 100644 svx/source/dialog/dlgctl3d.cxx create mode 100644 svx/source/dialog/dlgctrl.cxx create mode 100644 svx/source/dialog/dlgunit.hxx create mode 100644 svx/source/dialog/dlgutil.cxx create mode 100644 svx/source/dialog/docrecovery.cxx create mode 100644 svx/source/dialog/fntctrl.cxx create mode 100644 svx/source/dialog/fontwork.cxx create mode 100644 svx/source/dialog/framelink.cxx create mode 100644 svx/source/dialog/framelinkarray.cxx create mode 100644 svx/source/dialog/frmdirlbox.cxx create mode 100644 svx/source/dialog/frmsel.cxx create mode 100644 svx/source/dialog/graphctl.cxx create mode 100644 svx/source/dialog/grfflt.cxx create mode 100644 svx/source/dialog/hdft.cxx create mode 100644 svx/source/dialog/hexcolorcontrol.cxx create mode 100644 svx/source/dialog/hyperdlg.cxx create mode 100644 svx/source/dialog/imapdlg.cxx create mode 100644 svx/source/dialog/imapimp.hxx create mode 100644 svx/source/dialog/imapwnd.cxx create mode 100644 svx/source/dialog/imapwnd.hxx create mode 100644 svx/source/dialog/langbox.cxx create mode 100644 svx/source/dialog/linkwarn.cxx create mode 100644 svx/source/dialog/measctrl.cxx create mode 100644 svx/source/dialog/optgrid.cxx create mode 100644 svx/source/dialog/page.hrc create mode 100644 svx/source/dialog/pagectrl.cxx create mode 100644 svx/source/dialog/pagenumberlistbox.cxx create mode 100644 svx/source/dialog/papersizelistbox.cxx create mode 100644 svx/source/dialog/paraprev.cxx create mode 100644 svx/source/dialog/passwd.cxx create mode 100644 svx/source/dialog/relfld.cxx create mode 100644 svx/source/dialog/rlrcitem.cxx create mode 100644 svx/source/dialog/rlrcitem.hxx create mode 100644 svx/source/dialog/rubydialog.cxx create mode 100644 svx/source/dialog/rulritem.cxx create mode 100644 svx/source/dialog/samecontentlistbox.cxx create mode 100644 svx/source/dialog/searchcharmap.cxx create mode 100644 svx/source/dialog/spacinglistbox.cxx create mode 100644 svx/source/dialog/srchctrl.cxx create mode 100644 svx/source/dialog/srchctrl.hxx create mode 100644 svx/source/dialog/srchdlg.cxx create mode 100644 svx/source/dialog/strarray.cxx create mode 100644 svx/source/dialog/svxbmpnumvalueset.cxx create mode 100644 svx/source/dialog/svxdlg.cxx create mode 100644 svx/source/dialog/svxgrahicitem.cxx create mode 100644 svx/source/dialog/svxruler.cxx create mode 100644 svx/source/dialog/swframeexample.cxx create mode 100644 svx/source/dialog/swframeposstrings.cxx create mode 100644 svx/source/dialog/txencbox.cxx create mode 100644 svx/source/dialog/txenctab.cxx create mode 100644 svx/source/dialog/weldeditview.cxx create mode 100644 svx/source/engine3d/camera3d.cxx create mode 100644 svx/source/engine3d/cube3d.cxx create mode 100644 svx/source/engine3d/deflt3d.cxx create mode 100644 svx/source/engine3d/dragmt3d.cxx create mode 100644 svx/source/engine3d/e3dsceneupdater.cxx create mode 100644 svx/source/engine3d/e3dundo.cxx create mode 100644 svx/source/engine3d/extrud3d.cxx create mode 100644 svx/source/engine3d/float3d.cxx create mode 100644 svx/source/engine3d/helperhittest3d.cxx create mode 100644 svx/source/engine3d/helperminimaldepth3d.cxx create mode 100644 svx/source/engine3d/helperminimaldepth3d.hxx create mode 100644 svx/source/engine3d/lathe3d.cxx create mode 100644 svx/source/engine3d/obj3d.cxx create mode 100644 svx/source/engine3d/objfac3d.cxx create mode 100644 svx/source/engine3d/polygn3d.cxx create mode 100644 svx/source/engine3d/scene3d.cxx create mode 100644 svx/source/engine3d/sphere3d.cxx create mode 100644 svx/source/engine3d/svx3ditems.cxx create mode 100644 svx/source/engine3d/view3d.cxx create mode 100644 svx/source/engine3d/view3d1.cxx create mode 100644 svx/source/engine3d/viewpt3d2.cxx create mode 100644 svx/source/fmcomp/dbaexchange.cxx create mode 100644 svx/source/fmcomp/dbaobjectex.cxx create mode 100644 svx/source/fmcomp/fmgridcl.cxx create mode 100644 svx/source/fmcomp/fmgridif.cxx create mode 100644 svx/source/fmcomp/gridcell.cxx create mode 100644 svx/source/fmcomp/gridcols.cxx create mode 100644 svx/source/fmcomp/gridctrl.cxx create mode 100644 svx/source/fmcomp/xmlexchg.cxx create mode 100644 svx/source/form/ParseContext.cxx create mode 100644 svx/source/form/dataaccessdescriptor.cxx create mode 100644 svx/source/form/databaselocationinput.cxx create mode 100644 svx/source/form/datalistener.cxx create mode 100644 svx/source/form/datanavi.cxx create mode 100644 svx/source/form/dbcharsethelper.cxx create mode 100644 svx/source/form/delayedevent.cxx create mode 100644 svx/source/form/filtnav.cxx create mode 100644 svx/source/form/fmPropBrw.cxx create mode 100644 svx/source/form/fmcontrolbordermanager.cxx create mode 100644 svx/source/form/fmcontrollayout.cxx create mode 100644 svx/source/form/fmdmod.cxx create mode 100644 svx/source/form/fmdocumentclassification.cxx create mode 100644 svx/source/form/fmdpage.cxx create mode 100644 svx/source/form/fmexch.cxx create mode 100644 svx/source/form/fmexpl.cxx create mode 100644 svx/source/form/fmmodel.cxx create mode 100644 svx/source/form/fmobj.cxx create mode 100644 svx/source/form/fmobjfac.cxx create mode 100644 svx/source/form/fmpage.cxx create mode 100644 svx/source/form/fmpgeimp.cxx create mode 100644 svx/source/form/fmscriptingenv.cxx create mode 100644 svx/source/form/fmservs.cxx create mode 100644 svx/source/form/fmshell.cxx create mode 100644 svx/source/form/fmshimp.cxx create mode 100644 svx/source/form/fmsrccfg.cxx create mode 100644 svx/source/form/fmsrcimp.cxx create mode 100644 svx/source/form/fmtextcontroldialogs.cxx create mode 100644 svx/source/form/fmtextcontrolfeature.cxx create mode 100644 svx/source/form/fmtextcontrolshell.cxx create mode 100644 svx/source/form/fmtools.cxx create mode 100644 svx/source/form/fmundo.cxx create mode 100644 svx/source/form/fmview.cxx create mode 100644 svx/source/form/fmvwimp.cxx create mode 100644 svx/source/form/formcontrolfactory.cxx create mode 100644 svx/source/form/formcontroller.cxx create mode 100644 svx/source/form/formcontrolling.cxx create mode 100644 svx/source/form/formdispatchinterceptor.cxx create mode 100644 svx/source/form/formfeaturedispatcher.cxx create mode 100644 svx/source/form/formtoolbars.cxx create mode 100644 svx/source/form/labelitemwindow.cxx create mode 100644 svx/source/form/legacyformcontroller.cxx create mode 100644 svx/source/form/navigatortree.cxx create mode 100644 svx/source/form/navigatortreemodel.cxx create mode 100644 svx/source/form/sdbdatacolumn.cxx create mode 100644 svx/source/form/sqlparserclient.cxx create mode 100644 svx/source/form/tabwin.cxx create mode 100644 svx/source/form/tbxform.cxx create mode 100644 svx/source/form/typemap.cxx create mode 100644 svx/source/form/xfm_addcondition.cxx create mode 100644 svx/source/gallery2/GalleryControl.cxx create mode 100644 svx/source/gallery2/codec.cxx create mode 100644 svx/source/gallery2/codec.hxx create mode 100644 svx/source/gallery2/galbrws1.cxx create mode 100644 svx/source/gallery2/galbrws1.hxx create mode 100644 svx/source/gallery2/galbrws2.cxx create mode 100644 svx/source/gallery2/galctrl.cxx create mode 100644 svx/source/gallery2/galexpl.cxx create mode 100644 svx/source/gallery2/galini.cxx create mode 100644 svx/source/gallery2/gallery1.cxx create mode 100644 svx/source/gallery2/gallerydrawmodel.hxx create mode 100644 svx/source/gallery2/galmisc.cxx create mode 100644 svx/source/gallery2/galobj.cxx create mode 100644 svx/source/gallery2/galtheme.cxx create mode 100644 svx/source/gengal/gengal.cxx create mode 100755 svx/source/gengal/gengal.sh create mode 100644 svx/source/inc/AccessibleFrameSelector.hxx create mode 100644 svx/source/inc/DefaultShapesPanel.hxx create mode 100644 svx/source/inc/GraphCtlAccessibleContext.hxx create mode 100644 svx/source/inc/ShapesUtil.hxx create mode 100644 svx/source/inc/cell.hxx create mode 100644 svx/source/inc/celltypes.hxx create mode 100644 svx/source/inc/charmapacc.hxx create mode 100644 svx/source/inc/clonelist.hxx create mode 100644 svx/source/inc/datalistener.hxx create mode 100644 svx/source/inc/datanavi.hxx create mode 100644 svx/source/inc/delayedevent.hxx create mode 100644 svx/source/inc/docrecovery.hxx create mode 100644 svx/source/inc/filtnav.hxx create mode 100644 svx/source/inc/findtextfield.hxx create mode 100644 svx/source/inc/fmPropBrw.hxx create mode 100644 svx/source/inc/fmcontrolbordermanager.hxx create mode 100644 svx/source/inc/fmcontrollayout.hxx create mode 100644 svx/source/inc/fmdocumentclassification.hxx create mode 100644 svx/source/inc/fmexch.hxx create mode 100644 svx/source/inc/fmexpl.hxx create mode 100644 svx/source/inc/fmobj.hxx create mode 100644 svx/source/inc/fmpgeimp.hxx create mode 100644 svx/source/inc/fmprop.hxx create mode 100644 svx/source/inc/fmscriptingenv.hxx create mode 100644 svx/source/inc/fmservs.hxx create mode 100644 svx/source/inc/fmshimp.hxx create mode 100644 svx/source/inc/fmslotinvalidator.hxx create mode 100644 svx/source/inc/fmtextcontroldialogs.hxx create mode 100644 svx/source/inc/fmtextcontrolfeature.hxx create mode 100644 svx/source/inc/fmtextcontrolshell.hxx create mode 100644 svx/source/inc/fmundo.hxx create mode 100644 svx/source/inc/fmurl.hxx create mode 100644 svx/source/inc/fmvwimp.hxx create mode 100644 svx/source/inc/formcontrolfactory.hxx create mode 100644 svx/source/inc/formcontroller.hxx create mode 100644 svx/source/inc/formcontrolling.hxx create mode 100644 svx/source/inc/formdispatchinterceptor.hxx create mode 100644 svx/source/inc/formfeaturedispatcher.hxx create mode 100644 svx/source/inc/formtoolbars.hxx create mode 100644 svx/source/inc/frmselimpl.hxx create mode 100644 svx/source/inc/gridcell.hxx create mode 100644 svx/source/inc/gridcols.hxx create mode 100644 svx/source/inc/sdbdatacolumn.hxx create mode 100644 svx/source/inc/sqlparserclient.hxx create mode 100644 svx/source/inc/svdobjplusdata.hxx create mode 100644 svx/source/inc/svdobjuserdatalist.hxx create mode 100644 svx/source/inc/svdoutlinercache.hxx create mode 100644 svx/source/inc/svdpdf.hxx create mode 100644 svx/source/inc/svxpixelctlaccessiblecontext.hxx create mode 100644 svx/source/inc/svxrectctaccessiblecontext.hxx create mode 100644 svx/source/inc/tablemodel.hxx create mode 100644 svx/source/inc/tabwin.hxx create mode 100644 svx/source/inc/tbxform.hxx create mode 100644 svx/source/inc/treevisitor.hxx create mode 100644 svx/source/inc/xfm_addcondition.hxx create mode 100644 svx/source/inc/xmlxtexp.hxx create mode 100644 svx/source/inc/xmlxtimp.hxx create mode 100644 svx/source/items/SmartTagItem.cxx create mode 100644 svx/source/items/algitem.cxx create mode 100644 svx/source/items/autoformathelper.cxx create mode 100644 svx/source/items/chrtitem.cxx create mode 100644 svx/source/items/clipfmtitem.cxx create mode 100644 svx/source/items/customshapeitem.cxx create mode 100644 svx/source/items/drawitem.cxx create mode 100644 svx/source/items/e3ditem.cxx create mode 100644 svx/source/items/galleryitem.cxx create mode 100644 svx/source/items/grfitem.cxx create mode 100644 svx/source/items/hlnkitem.cxx create mode 100644 svx/source/items/legacyitem.cxx create mode 100644 svx/source/items/numfmtsh.cxx create mode 100644 svx/source/items/numinf.cxx create mode 100644 svx/source/items/ofaitem.cxx create mode 100644 svx/source/items/pageitem.cxx create mode 100644 svx/source/items/postattr.cxx create mode 100644 svx/source/items/rotmodit.cxx create mode 100644 svx/source/items/svxerr.cxx create mode 100644 svx/source/items/viewlayoutitem.cxx create mode 100644 svx/source/items/zoomslideritem.cxx create mode 100644 svx/source/mnuctrls/clipboardctl.cxx create mode 100644 svx/source/mnuctrls/smarttagmenu.cxx create mode 100644 svx/source/sdr/animation/animationstate.cxx create mode 100644 svx/source/sdr/animation/objectanimator.cxx create mode 100644 svx/source/sdr/animation/scheduler.cxx create mode 100644 svx/source/sdr/attribute/sdrallfillattributeshelper.cxx create mode 100644 svx/source/sdr/attribute/sdreffectstextattribute.cxx create mode 100644 svx/source/sdr/attribute/sdrfilltextattribute.cxx create mode 100644 svx/source/sdr/attribute/sdrformtextattribute.cxx create mode 100644 svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx create mode 100644 svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx create mode 100644 svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx create mode 100644 svx/source/sdr/attribute/sdrtextattribute.cxx create mode 100644 svx/source/sdr/contact/displayinfo.cxx create mode 100644 svx/source/sdr/contact/objectcontact.cxx create mode 100644 svx/source/sdr/contact/objectcontactofobjlistpainter.cxx create mode 100644 svx/source/sdr/contact/objectcontactofpageview.cxx create mode 100644 svx/source/sdr/contact/sdrmediawindow.cxx create mode 100644 svx/source/sdr/contact/sdrmediawindow.hxx create mode 100644 svx/source/sdr/contact/viewcontact.cxx create mode 100644 svx/source/sdr/contact/viewcontactofe3d.cxx create mode 100644 svx/source/sdr/contact/viewcontactofe3dcube.cxx create mode 100644 svx/source/sdr/contact/viewcontactofe3dextrude.cxx create mode 100644 svx/source/sdr/contact/viewcontactofe3dlathe.cxx create mode 100644 svx/source/sdr/contact/viewcontactofe3dpolygon.cxx create mode 100644 svx/source/sdr/contact/viewcontactofe3dscene.cxx create mode 100644 svx/source/sdr/contact/viewcontactofe3dsphere.cxx create mode 100644 svx/source/sdr/contact/viewcontactofgraphic.cxx create mode 100644 svx/source/sdr/contact/viewcontactofgroup.cxx create mode 100644 svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx create mode 100644 svx/source/sdr/contact/viewcontactofpageobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrcircobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdredgeobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrole2obj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrpage.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrpathobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofsdrrectobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactoftextobj.cxx create mode 100644 svx/source/sdr/contact/viewcontactofunocontrol.cxx create mode 100644 svx/source/sdr/contact/viewcontactofvirtobj.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontact.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofe3d.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofgraphic.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofgroup.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofpageobj.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx create mode 100644 svx/source/sdr/contact/viewobjectcontactredirector.cxx create mode 100644 svx/source/sdr/misc/ImageMapInfo.cxx create mode 100644 svx/source/sdr/overlay/overlayanimatedbitmapex.cxx create mode 100644 svx/source/sdr/overlay/overlaybitmapex.cxx create mode 100644 svx/source/sdr/overlay/overlaycrosshair.cxx create mode 100644 svx/source/sdr/overlay/overlayhandle.cxx create mode 100644 svx/source/sdr/overlay/overlayhelpline.cxx create mode 100644 svx/source/sdr/overlay/overlayline.cxx create mode 100644 svx/source/sdr/overlay/overlaymanager.cxx create mode 100644 svx/source/sdr/overlay/overlaymanagerbuffered.cxx create mode 100644 svx/source/sdr/overlay/overlayobject.cxx create mode 100644 svx/source/sdr/overlay/overlayobjectcell.cxx create mode 100644 svx/source/sdr/overlay/overlayobjectlist.cxx create mode 100644 svx/source/sdr/overlay/overlaypolypolygon.cxx create mode 100644 svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx create mode 100644 svx/source/sdr/overlay/overlayrectangle.cxx create mode 100644 svx/source/sdr/overlay/overlayrollingrectangle.cxx create mode 100644 svx/source/sdr/overlay/overlayselection.cxx create mode 100644 svx/source/sdr/overlay/overlaytools.cxx create mode 100644 svx/source/sdr/overlay/overlaytriangle.cxx create mode 100644 svx/source/sdr/primitive2d/primitivefactory2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrattributecreator.cxx create mode 100644 svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrdecompositiontools.cxx create mode 100644 svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrole2primitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrprimitivetools.cxx create mode 100644 svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx create mode 100644 svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx create mode 100644 svx/source/sdr/primitive3d/sdrattributecreator3d.cxx create mode 100644 svx/source/sdr/properties/attributeproperties.cxx create mode 100644 svx/source/sdr/properties/captionproperties.cxx create mode 100644 svx/source/sdr/properties/circleproperties.cxx create mode 100644 svx/source/sdr/properties/connectorproperties.cxx create mode 100644 svx/source/sdr/properties/customshapeproperties.cxx create mode 100644 svx/source/sdr/properties/defaultproperties.cxx create mode 100644 svx/source/sdr/properties/e3dcompoundproperties.cxx create mode 100644 svx/source/sdr/properties/e3dextrudeproperties.cxx create mode 100644 svx/source/sdr/properties/e3dlatheproperties.cxx create mode 100644 svx/source/sdr/properties/e3dproperties.cxx create mode 100644 svx/source/sdr/properties/e3dsceneproperties.cxx create mode 100644 svx/source/sdr/properties/e3dsphereproperties.cxx create mode 100644 svx/source/sdr/properties/emptyproperties.cxx create mode 100644 svx/source/sdr/properties/graphicproperties.cxx create mode 100644 svx/source/sdr/properties/groupproperties.cxx create mode 100644 svx/source/sdr/properties/itemsettools.cxx create mode 100644 svx/source/sdr/properties/measureproperties.cxx create mode 100644 svx/source/sdr/properties/oleproperties.cxx create mode 100644 svx/source/sdr/properties/pageproperties.cxx create mode 100644 svx/source/sdr/properties/properties.cxx create mode 100644 svx/source/sdr/properties/rectangleproperties.cxx create mode 100644 svx/source/sdr/properties/textproperties.cxx create mode 100644 svx/source/sidebar/ContextChangeEventMultiplexer.cxx create mode 100644 svx/source/sidebar/EmptyPanel.cxx create mode 100644 svx/source/sidebar/EmptyPanel.hxx create mode 100644 svx/source/sidebar/PanelFactory.cxx create mode 100644 svx/source/sidebar/SelectionAnalyzer.cxx create mode 100644 svx/source/sidebar/SelectionChangeHandler.cxx create mode 100644 svx/source/sidebar/area/AreaPropertyPanel.cxx create mode 100644 svx/source/sidebar/area/AreaPropertyPanel.hxx create mode 100644 svx/source/sidebar/area/AreaPropertyPanelBase.cxx create mode 100644 svx/source/sidebar/area/AreaTransparencyGradientPopup.cxx create mode 100644 svx/source/sidebar/glow/GlowPropertyPanel.cxx create mode 100644 svx/source/sidebar/glow/GlowPropertyPanel.hxx create mode 100644 svx/source/sidebar/graphic/GraphicPropertyPanel.cxx create mode 100644 svx/source/sidebar/graphic/GraphicPropertyPanel.hxx create mode 100644 svx/source/sidebar/inspector/InspectorTextPanel.cxx create mode 100644 svx/source/sidebar/inspector/InspectorTextPanel.hxx create mode 100644 svx/source/sidebar/line/LinePropertyPanel.cxx create mode 100644 svx/source/sidebar/line/LinePropertyPanel.hxx create mode 100644 svx/source/sidebar/line/LinePropertyPanelBase.cxx create mode 100644 svx/source/sidebar/line/LineWidthPopup.cxx create mode 100644 svx/source/sidebar/line/LineWidthValueSet.cxx create mode 100644 svx/source/sidebar/line/LineWidthValueSet.hxx create mode 100644 svx/source/sidebar/lists/ListsPropertyPanel.cxx create mode 100644 svx/source/sidebar/lists/ListsPropertyPanel.hxx create mode 100644 svx/source/sidebar/media/MediaPlaybackPanel.cxx create mode 100644 svx/source/sidebar/media/MediaPlaybackPanel.hxx create mode 100644 svx/source/sidebar/nbdtmg.cxx create mode 100644 svx/source/sidebar/nbdtmgfact.cxx create mode 100644 svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx create mode 100644 svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx create mode 100644 svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx create mode 100644 svx/source/sidebar/paragraph/ParaPropertyPanel.cxx create mode 100644 svx/source/sidebar/paragraph/ParaPropertyPanel.hxx create mode 100644 svx/source/sidebar/paragraph/ParaSpacingControl.cxx create mode 100644 svx/source/sidebar/paragraph/ParaSpacingWindow.cxx create mode 100644 svx/source/sidebar/paragraph/ParaSpacingWindow.hxx create mode 100644 svx/source/sidebar/possize/PosSizePropertyPanel.cxx create mode 100644 svx/source/sidebar/possize/PosSizePropertyPanel.hxx create mode 100644 svx/source/sidebar/shadow/ShadowPropertyPanel.cxx create mode 100644 svx/source/sidebar/shadow/ShadowPropertyPanel.hxx create mode 100644 svx/source/sidebar/shapes/DefaultShapesPanel.cxx create mode 100644 svx/source/sidebar/shapes/ShapesUtil.cxx create mode 100644 svx/source/sidebar/softedge/SoftEdgePropertyPanel.cxx create mode 100644 svx/source/sidebar/softedge/SoftEdgePropertyPanel.hxx create mode 100644 svx/source/sidebar/styles/StylesPropertyPanel.cxx create mode 100644 svx/source/sidebar/styles/StylesPropertyPanel.hxx create mode 100644 svx/source/sidebar/text/TextCharacterSpacingControl.cxx create mode 100644 svx/source/sidebar/text/TextCharacterSpacingControl.hxx create mode 100644 svx/source/sidebar/text/TextCharacterSpacingPopup.cxx create mode 100644 svx/source/sidebar/text/TextPropertyPanel.cxx create mode 100644 svx/source/sidebar/text/TextPropertyPanel.hxx create mode 100644 svx/source/sidebar/text/TextUnderlineControl.cxx create mode 100644 svx/source/sidebar/text/TextUnderlineControl.hxx create mode 100644 svx/source/sidebar/text/TextUnderlinePopup.cxx create mode 100644 svx/source/sidebar/tools/ValueSetWithTextControl.cxx create mode 100644 svx/source/smarttags/SmartTagMgr.cxx create mode 100644 svx/source/stbctrls/insctrl.cxx create mode 100644 svx/source/stbctrls/modctrl.cxx create mode 100644 svx/source/stbctrls/modctrl_internal.hxx create mode 100644 svx/source/stbctrls/pszctrl.cxx create mode 100644 svx/source/stbctrls/selctrl.cxx create mode 100644 svx/source/stbctrls/stbctrls.h create mode 100644 svx/source/stbctrls/xmlsecctrl.cxx create mode 100644 svx/source/stbctrls/zoomctrl.cxx create mode 100644 svx/source/stbctrls/zoomsliderctrl.cxx create mode 100644 svx/source/styles/ColorSets.cxx create mode 100644 svx/source/styles/CommonStyleManager.cxx create mode 100644 svx/source/styles/CommonStylePreviewRenderer.cxx create mode 100644 svx/source/svdraw/ActionDescriptionProvider.cxx create mode 100644 svx/source/svdraw/charthelper.cxx create mode 100644 svx/source/svdraw/clonelist.cxx create mode 100644 svx/source/svdraw/gradtrns.cxx create mode 100644 svx/source/svdraw/gradtrns.hxx create mode 100644 svx/source/svdraw/polypolygoneditor.cxx create mode 100644 svx/source/svdraw/presetooxhandleadjustmentrelations.cxx create mode 100644 svx/source/svdraw/presetooxhandleadjustmentrelations.hxx create mode 100644 svx/source/svdraw/sdrhittesthelper.cxx create mode 100644 svx/source/svdraw/sdrmasterpagedescriptor.cxx create mode 100644 svx/source/svdraw/sdrpagewindow.cxx create mode 100644 svx/source/svdraw/sdrpaintwindow.cxx create mode 100644 svx/source/svdraw/sdrundomanager.cxx create mode 100644 svx/source/svdraw/selectioncontroller.cxx create mode 100644 svx/source/svdraw/svdattr.cxx create mode 100644 svx/source/svdraw/svdcrtv.cxx create mode 100644 svx/source/svdraw/svddrag.cxx create mode 100644 svx/source/svdraw/svddrgm1.hxx create mode 100644 svx/source/svdraw/svddrgmt.cxx create mode 100644 svx/source/svdraw/svddrgv.cxx create mode 100644 svx/source/svdraw/svdedtv.cxx create mode 100644 svx/source/svdraw/svdedtv1.cxx create mode 100644 svx/source/svdraw/svdedtv2.cxx create mode 100644 svx/source/svdraw/svdedxv.cxx create mode 100644 svx/source/svdraw/svdetc.cxx create mode 100644 svx/source/svdraw/svdfmtf.cxx create mode 100644 svx/source/svdraw/svdfmtf.hxx create mode 100644 svx/source/svdraw/svdglev.cxx create mode 100644 svx/source/svdraw/svdglue.cxx create mode 100644 svx/source/svdraw/svdhdl.cxx create mode 100644 svx/source/svdraw/svdhlpln.cxx create mode 100644 svx/source/svdraw/svditer.cxx create mode 100644 svx/source/svdraw/svdlayer.cxx create mode 100644 svx/source/svdraw/svdmark.cxx create mode 100644 svx/source/svdraw/svdmodel.cxx create mode 100644 svx/source/svdraw/svdmrkv.cxx create mode 100644 svx/source/svdraw/svdmrkv1.cxx create mode 100644 svx/source/svdraw/svdoashp.cxx create mode 100644 svx/source/svdraw/svdoattr.cxx create mode 100644 svx/source/svdraw/svdobj.cxx create mode 100644 svx/source/svdraw/svdobjplusdata.cxx create mode 100644 svx/source/svdraw/svdobjuserdatalist.cxx create mode 100644 svx/source/svdraw/svdocapt.cxx create mode 100644 svx/source/svdraw/svdocirc.cxx create mode 100644 svx/source/svdraw/svdoedge.cxx create mode 100644 svx/source/svdraw/svdograf.cxx create mode 100644 svx/source/svdraw/svdogrp.cxx create mode 100644 svx/source/svdraw/svdomeas.cxx create mode 100644 svx/source/svdraw/svdomedia.cxx create mode 100644 svx/source/svdraw/svdoole2.cxx create mode 100644 svx/source/svdraw/svdopage.cxx create mode 100644 svx/source/svdraw/svdopath.cxx create mode 100644 svx/source/svdraw/svdorect.cxx create mode 100644 svx/source/svdraw/svdotext.cxx create mode 100644 svx/source/svdraw/svdotextdecomposition.cxx create mode 100644 svx/source/svdraw/svdotextpathdecomposition.cxx create mode 100644 svx/source/svdraw/svdotxat.cxx create mode 100644 svx/source/svdraw/svdotxdr.cxx create mode 100644 svx/source/svdraw/svdotxed.cxx create mode 100644 svx/source/svdraw/svdotxfl.cxx create mode 100644 svx/source/svdraw/svdotxln.cxx create mode 100644 svx/source/svdraw/svdotxtr.cxx create mode 100644 svx/source/svdraw/svdouno.cxx create mode 100644 svx/source/svdraw/svdoutl.cxx create mode 100644 svx/source/svdraw/svdoutlinercache.cxx create mode 100644 svx/source/svdraw/svdovirt.cxx create mode 100644 svx/source/svdraw/svdpage.cxx create mode 100644 svx/source/svdraw/svdpagv.cxx create mode 100644 svx/source/svdraw/svdpdf.cxx create mode 100644 svx/source/svdraw/svdpntv.cxx create mode 100644 svx/source/svdraw/svdpoev.cxx create mode 100644 svx/source/svdraw/svdsnpv.cxx create mode 100644 svx/source/svdraw/svdtext.cxx create mode 100644 svx/source/svdraw/svdtrans.cxx create mode 100644 svx/source/svdraw/svdundo.cxx create mode 100644 svx/source/svdraw/svdview.cxx create mode 100644 svx/source/svdraw/svdviter.cxx create mode 100644 svx/source/svdraw/svdxcgv.cxx create mode 100644 svx/source/svdraw/textchain.cxx create mode 100644 svx/source/svdraw/textchaincursor.cxx create mode 100644 svx/source/svdraw/textchainflow.cxx create mode 100644 svx/source/table/accessiblecell.cxx create mode 100644 svx/source/table/accessiblecell.hxx create mode 100644 svx/source/table/accessibletableshape.cxx create mode 100644 svx/source/table/cell.cxx create mode 100644 svx/source/table/cellcursor.cxx create mode 100644 svx/source/table/cellcursor.hxx create mode 100644 svx/source/table/cellrange.cxx create mode 100644 svx/source/table/cellrange.hxx create mode 100644 svx/source/table/propertyset.cxx create mode 100644 svx/source/table/propertyset.hxx create mode 100644 svx/source/table/svdotable.cxx create mode 100644 svx/source/table/tablecolumn.cxx create mode 100644 svx/source/table/tablecolumn.hxx create mode 100644 svx/source/table/tablecolumns.cxx create mode 100644 svx/source/table/tablecolumns.hxx create mode 100644 svx/source/table/tablecontroller.cxx create mode 100644 svx/source/table/tabledesign.cxx create mode 100644 svx/source/table/tablehandles.cxx create mode 100644 svx/source/table/tablehandles.hxx create mode 100644 svx/source/table/tablelayouter.cxx create mode 100644 svx/source/table/tablelayouter.hxx create mode 100644 svx/source/table/tablemodel.cxx create mode 100644 svx/source/table/tablerow.cxx create mode 100644 svx/source/table/tablerow.hxx create mode 100644 svx/source/table/tablerows.cxx create mode 100644 svx/source/table/tablerows.hxx create mode 100644 svx/source/table/tablertfexporter.cxx create mode 100644 svx/source/table/tablertfimporter.cxx create mode 100644 svx/source/table/tableundo.cxx create mode 100644 svx/source/table/tableundo.hxx create mode 100644 svx/source/table/viewcontactoftableobj.cxx create mode 100644 svx/source/table/viewcontactoftableobj.hxx create mode 100644 svx/source/tbxctrls/Palette.cxx create mode 100644 svx/source/tbxctrls/PaletteManager.cxx create mode 100644 svx/source/tbxctrls/SvxColorChildWindow.cxx create mode 100644 svx/source/tbxctrls/SvxColorValueSet.cxx create mode 100644 svx/source/tbxctrls/SvxPresetListBox.cxx create mode 100644 svx/source/tbxctrls/bulletsnumbering.cxx create mode 100644 svx/source/tbxctrls/colrctrl.cxx create mode 100644 svx/source/tbxctrls/extrusioncontrols.cxx create mode 100644 svx/source/tbxctrls/extrusioncontrols.hxx create mode 100644 svx/source/tbxctrls/fillctrl.cxx create mode 100644 svx/source/tbxctrls/fontworkgallery.cxx create mode 100644 svx/source/tbxctrls/formatpaintbrushctrl.cxx create mode 100644 svx/source/tbxctrls/grafctrl.cxx create mode 100644 svx/source/tbxctrls/itemwin.cxx create mode 100644 svx/source/tbxctrls/layctrl.cxx create mode 100644 svx/source/tbxctrls/lboxctrl.cxx create mode 100644 svx/source/tbxctrls/linectrl.cxx create mode 100644 svx/source/tbxctrls/linemetricbox.hxx create mode 100644 svx/source/tbxctrls/linewidthctrl.cxx create mode 100644 svx/source/tbxctrls/tbcontrl.cxx create mode 100644 svx/source/tbxctrls/tbunocontroller.cxx create mode 100644 svx/source/tbxctrls/tbunosearchcontrollers.cxx create mode 100644 svx/source/tbxctrls/tbxcolor.cxx create mode 100644 svx/source/tbxctrls/tbxcolorupdate.cxx create mode 100644 svx/source/tbxctrls/tbxdrctl.cxx create mode 100644 svx/source/tbxctrls/verttexttbxctrl.cxx create mode 100644 svx/source/toolbars/extrusionbar.cxx create mode 100644 svx/source/toolbars/fontworkbar.cxx create mode 100644 svx/source/uitest/sdrobject.cxx create mode 100644 svx/source/uitest/uiobject.cxx create mode 100644 svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.cxx create mode 100644 svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.hxx create mode 100644 svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.cxx create mode 100644 svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.hxx create mode 100644 svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.cxx create mode 100644 svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.hxx create mode 100644 svx/source/unodialogs/textconversiondlgs/services.cxx create mode 100644 svx/source/unodraw/UnoGraphicExporter.cxx create mode 100644 svx/source/unodraw/UnoGraphicExporter.hxx create mode 100644 svx/source/unodraw/UnoNameItemTable.cxx create mode 100644 svx/source/unodraw/UnoNameItemTable.hxx create mode 100644 svx/source/unodraw/UnoNamespaceMap.cxx create mode 100644 svx/source/unodraw/XPropertyTable.cxx create mode 100644 svx/source/unodraw/gluepts.cxx create mode 100644 svx/source/unodraw/gluepts.hxx create mode 100644 svx/source/unodraw/recoveryui.cxx create mode 100644 svx/source/unodraw/shapeimpl.hxx create mode 100644 svx/source/unodraw/shapepropertynotifier.cxx create mode 100644 svx/source/unodraw/tableshape.cxx create mode 100644 svx/source/unodraw/unobrushitemhelper.cxx create mode 100644 svx/source/unodraw/unobtabl.cxx create mode 100644 svx/source/unodraw/unoctabl.cxx create mode 100644 svx/source/unodraw/unodtabl.cxx create mode 100644 svx/source/unodraw/unogtabl.cxx create mode 100644 svx/source/unodraw/unohtabl.cxx create mode 100644 svx/source/unodraw/unomlstr.cxx create mode 100644 svx/source/unodraw/unomod.cxx create mode 100644 svx/source/unodraw/unomtabl.cxx create mode 100644 svx/source/unodraw/unopage.cxx create mode 100644 svx/source/unodraw/unopool.cxx create mode 100644 svx/source/unodraw/unoprov.cxx create mode 100644 svx/source/unodraw/unoshap2.cxx create mode 100644 svx/source/unodraw/unoshap3.cxx create mode 100644 svx/source/unodraw/unoshap4.cxx create mode 100644 svx/source/unodraw/unoshape.cxx create mode 100644 svx/source/unodraw/unoshcol.cxx create mode 100644 svx/source/unodraw/unoshtxt.cxx create mode 100644 svx/source/unodraw/unottabl.cxx create mode 100644 svx/source/unogallery/unogalitem.cxx create mode 100644 svx/source/unogallery/unogalitem.hxx create mode 100644 svx/source/unogallery/unogaltheme.cxx create mode 100644 svx/source/unogallery/unogaltheme.hxx create mode 100644 svx/source/unogallery/unogalthemeprovider.cxx create mode 100644 svx/source/xml/xmleohlp.cxx create mode 100644 svx/source/xml/xmlexport.cxx create mode 100644 svx/source/xml/xmlgrhlp.cxx create mode 100644 svx/source/xml/xmlxtexp.cxx create mode 100644 svx/source/xml/xmlxtimp.cxx create mode 100644 svx/source/xoutdev/XPropertyEntry.cxx create mode 100644 svx/source/xoutdev/_xoutbmp.cxx create mode 100644 svx/source/xoutdev/_xpoly.cxx create mode 100644 svx/source/xoutdev/xattr.cxx create mode 100644 svx/source/xoutdev/xattr2.cxx create mode 100644 svx/source/xoutdev/xattrbmp.cxx create mode 100644 svx/source/xoutdev/xpool.cxx create mode 100644 svx/source/xoutdev/xtabbtmp.cxx create mode 100644 svx/source/xoutdev/xtabcolr.cxx create mode 100644 svx/source/xoutdev/xtabdash.cxx create mode 100644 svx/source/xoutdev/xtabgrdt.cxx create mode 100644 svx/source/xoutdev/xtabhtch.cxx create mode 100644 svx/source/xoutdev/xtable.cxx create mode 100644 svx/source/xoutdev/xtablend.cxx create mode 100644 svx/source/xoutdev/xtabptrn.cxx (limited to 'svx/source') diff --git a/svx/source/accessibility/AccessibleControlShape.cxx b/svx/source/accessibility/AccessibleControlShape.cxx new file mode 100644 index 000000000..2eaf8448f --- /dev/null +++ b/svx/source/accessibility/AccessibleControlShape.cxx @@ -0,0 +1,881 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 OutputDevice* pViewWindow = maShapeTreeInfo.GetDevice(); + SdrUnoObj* pUnoObjectImpl = dynamic_cast( 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 ); + + 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, 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 ("Unknown accessible control shape"); + if (mxShape.is()) + { + aDG.AppendString ("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( maMutex ); + + // 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( maMutex ); + + // 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 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( ) +{ + 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 ) ); + } + } + Reference< XAccessibleRelationSet > xSet = pRelationSetHelper; + return xSet; +} + +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.GetDevice(), 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 = + static_cast< ::utl::AccessibleStateSetHelper* >( 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 + { + 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() ) + { + // 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 : 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 ) + { + // 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 +#include +#include +#include +#include +#include +#include + + +// Project-local header + + +#include "AccessibleEmptyEditSource.hxx" +#include + +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 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 Clone() const override { return nullptr; } + void UpdateData() override {} + SfxBroadcaster& GetBroadcaster() const override { return *const_cast(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& /*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& /*rpTxtColor*/, std::optional& /*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 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 AccessibleEmptyEditSource::Clone() const + { + if (!mpEditSource) + return nullptr; + + return mpEditSource->Clone(); + } + + void AccessibleEmptyEditSource::UpdateData() + { + if (mpEditSource) + mpEditSource->UpdateData(); + } + + SfxBroadcaster& AccessibleEmptyEditSource::GetBroadcaster() const + { + return *const_cast(this); + } + + void AccessibleEmptyEditSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) + { + const SdrHint* pSdrHint = ( rHint.GetId() == SfxHintId::ThisIsAnSdrHint ? static_cast(&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 +#include + +#include +#include + +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 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..d367121e4 --- /dev/null +++ b/svx/source/accessibility/AccessibleFrameSelector.cxx @@ -0,0 +1,382 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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; + utl::AccessibleStateSetHelper* pStateSetHelper = new utl::AccessibleStateSetHelper; + Reference< XAccessibleStateSet > xRet = pStateSetHelper; + + 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 xRet; +} + +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(meBorder)].first); +} + +OUString AccFrameSelectorChild::getAccessibleName( ) +{ + SolarMutexGuard aGuard; + IsValid(); + return SvxResId(RID_SVXSTR_FRMSEL_TEXTS[static_cast(meBorder)].first); +} + +Reference< XAccessibleRelationSet > AccFrameSelectorChild::getAccessibleRelationSet( ) +{ + SolarMutexGuard aGuard; + IsValid(); + Reference< XAccessibleRelationSet > xRet = new utl::AccessibleRelationSetHelper; + return xRet; +} + +Reference< XAccessibleStateSet > AccFrameSelectorChild::getAccessibleStateSet( ) +{ + SolarMutexGuard aGuard; + utl::AccessibleStateSetHelper* pStateSetHelper = new utl::AccessibleStateSetHelper; + Reference< XAccessibleStateSet > xRet = pStateSetHelper; + + 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 xRet; +} + +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..10f42222d --- /dev/null +++ b/svx/source/accessibility/AccessibleGraphicShape.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 + +#include +#include +#include + +#include +#include +#include +#include + +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(this)); + return aReturn; +} + + +void SAL_CALL + AccessibleGraphicShape::acquire() + throw () +{ + AccessibleShape::acquire (); +} + + +void SAL_CALL + AccessibleGraphicShape::release() + throw () +{ + AccessibleShape::release (); +} + +// XServiceInfo +OUString SAL_CALL + AccessibleGraphicShape::getImplementationName() +{ + return "AccessibleGraphicShape"; +} + + +css::uno::Sequence< OUString> SAL_CALL + AccessibleGraphicShape::getSupportedServiceNames() +{ + ThrowIfDisposed (); + // Get list of supported service names from base class... + uno::Sequence aServiceNames = + AccessibleShape::getSupportedServiceNames(); + sal_Int32 nCount (aServiceNames.getLength()); + + // ...and add additional names. + aServiceNames.realloc (nCount + 1); + aServiceNames[nCount] = "com.sun.star.drawing.AccessibleGraphicShape"; + + return aServiceNames; +} + +// XTypeProvider +uno::Sequence SAL_CALL + AccessibleGraphicShape::getTypes() +{ + // Get list of types from the context base implementation... + return comphelper::concatSequences(AccessibleShape::getTypes(), + uno::Sequence { cppu::UnoType::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 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..daf3fb29c --- /dev/null +++ b/svx/source/accessibility/AccessibleOLEShape.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 + +#include +#include +#include + +#include +#include + +#include +#include +#include + +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 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(this)); + return aReturn; +} + + +void SAL_CALL + AccessibleOLEShape::acquire() + throw () +{ + AccessibleShape::acquire (); +} + + +void SAL_CALL + AccessibleOLEShape::release() + throw () +{ + AccessibleShape::release (); +} + +// XServiceInfo +OUString SAL_CALL + AccessibleOLEShape::getImplementationName() +{ + return "AccessibleOLEShape"; +} + + +css::uno::Sequence< OUString> SAL_CALL + AccessibleOLEShape::getSupportedServiceNames() +{ + ThrowIfDisposed(); + // Get list of supported service names from base class... + uno::Sequence< OUString > aServiceNames = + AccessibleShape::getSupportedServiceNames(); + sal_Int32 nCount (aServiceNames.getLength()); + + // ...and add additional names. + aServiceNames.realloc (nCount + 1); + aServiceNames[nCount] = "com.sun.star.drawing.AccessibleOLEShape"; + + return aServiceNames; +} + +// XTypeProvider +uno::Sequence SAL_CALL AccessibleOLEShape::getTypes() +{ + // Get list of types from the context base implementation... + return comphelper::concatSequences(AccessibleShape::getTypes(), + uno::Sequence { cppu::UnoType::get() } ); +} + +// XAccessibleExtendedAttributes +uno::Any SAL_CALL AccessibleOLEShape::getExtendedAttributes() +{ + uno::Any strRet; + OUString style; + if( m_pShape ) + { + style = "style:" + static_cast(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 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..6842d7655 --- /dev/null +++ b/svx/source/accessibility/AccessibleShape.cxx @@ -0,0 +1,1343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "AccessibleEmptyEditSource.hxx" + +#include +#include + +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& rxSet, + const OUString& rsPropertyName) +{ + OUString sValue; + + if (rxSet.is()) + { + const Reference 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 = 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 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(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 xText (mxShape, uno::UNO_QUERY); + if (xText.is()) + { + SdrView* pView = maShapeTreeInfo.GetSdrView (); + const vcl::Window* pWindow = maShapeTreeInfo.GetWindow (); + if (pView != nullptr && pWindow != nullptr && mxShape.is()) + { + // #107948# Determine whether shape text is empty + SdrObject* pSdrObject = GetSdrObjectFromXShape(mxShape); + if( pSdrObject ) + { + SdrTextObj* pTextObj = dynamic_cast( 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(*pSdrObject, *pView, *pWindow) ) ); + } + else + { + // non-empty text -> use full-fledged edit source right away + mpText.reset( new AccessibleTextHelper( std::make_unique(*pSdrObject, nullptr, *pView, *pWindow) ) ); + } + if( pWindow->HasFocus() ) + mpText->SetFocus(); + + mpText->SetEventSource(this); + } + } + } +} + + +void AccessibleShape::UpdateStates() +{ + ::utl::AccessibleStateSetHelper* pStateSet = + static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if (pStateSet == 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 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) + pStateSet->AddState (AccessibleStateType::OPAQUE); + else + pStateSet->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) + pStateSet->AddState (AccessibleStateType::SELECTED); + else + pStateSet->RemoveState (AccessibleStateType::SELECTED); +} + +OUString AccessibleShape::GetStyle() +{ + 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 SAL_CALL + AccessibleShape::getAccessibleChild (sal_Int32 nIndex) +{ + ThrowIfDisposed (); + + uno::Reference 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(this)); + + return xChild; +} + +uno::Reference SAL_CALL + AccessibleShape::getAccessibleRelationSet() +{ + ::osl::MutexGuard aGuard (maMutex); + if (mpParent == nullptr) + return uno::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 uno::Reference(pRelationSet); +} + +/** Return a copy of the state set. + Possible states are: + ENABLED + SHOWING + VISIBLE +*/ +uno::Reference SAL_CALL + AccessibleShape::getAccessibleStateSet() +{ + ::osl::MutexGuard aGuard (maMutex); + + if (IsDisposed()) + { + // Return a minimal state set that only contains the DEFUNC state. + return AccessibleContextBase::getAccessibleStateSet (); + } + + ::utl::AccessibleStateSetHelper* pStateSet = + static_cast<::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + + if (!pStateSet) + return Reference(); + + // 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 xTempAcc = getAccessibleParent(); + if( xTempAcc.is() ) + { + css::uno::Reference + xTempAccContext = xTempAcc->getAccessibleContext(); + if( xTempAccContext.is() ) + { + css::uno::Reference rState = + xTempAccContext->getAccessibleStateSet(); + if (rState.is()) + { + css::uno::Sequence 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 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 SAL_CALL + AccessibleShape::getAccessibleAtPoint ( + const awt::Point& aPoint) +{ + ::osl::MutexGuard aGuard (maMutex); + + sal_Int32 nChildCount = getAccessibleChildCount (); + for (sal_Int32 i=0; i xChild (getAccessibleChild (i)); + if (xChild.is()) + { + Reference 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(); +} + + +awt::Rectangle SAL_CALL AccessibleShape::getBounds() +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard (maMutex); + + ThrowIfDisposed (); + awt::Rectangle aBoundingBox; + if ( mxShape.is() ) + { + + static const char sBoundRectName[] = "BoundRect"; + static const char sAnchorPositionName[] = "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 xSet (mxShape, uno::UNO_QUERY); + Reference 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(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 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.getX(), + aBBox.getY(), + 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 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 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 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.SetTransparency(0xff); + } + else + { + nTrans = short(256 - nTrans / 100. * 256); + crBk.SetTransparency(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& rxListener) +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + uno::Reference xThis ( + static_cast(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& 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(this), + static_cast(this), + static_cast< css::accessibility::XAccessibleSelection* >(this), + static_cast< css::accessibility::XAccessibleExtendedAttributes* >(this), + static_cast(this), + static_cast(this), + static_cast(this), + static_cast(this) + ); + return aReturn; +} + + +void SAL_CALL + AccessibleShape::acquire() + throw () +{ + AccessibleContextBase::acquire (); +} + + +void SAL_CALL + AccessibleShape::release() + throw () +{ + AccessibleContextBase::release (); +} + +// XAccessibleSelection +void SAL_CALL AccessibleShape::selectAccessibleChild( sal_Int32 ) +{ +} + + +sal_Bool SAL_CALL AccessibleShape::isAccessibleChildSelected( sal_Int32 nChildIndex ) +{ + uno::Reference xAcc = getAccessibleChild( nChildIndex ); + uno::Reference 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; + + uno::Sequence 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 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(); +} + + +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 SAL_CALL + AccessibleShape::getSupportedServiceNames() +{ + ThrowIfDisposed (); + // Get list of supported service names from base class... + uno::Sequence aServiceNames = + AccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nCount (aServiceNames.getLength()); + + // ...and add additional names. + aServiceNames.realloc (nCount + 1); + aServiceNames[nCount] = "com.sun.star.drawing.AccessibleShape"; + + return aServiceNames; +} + +// XTypeProvider +uno::Sequence SAL_CALL + AccessibleShape::getTypes() +{ + ThrowIfDisposed (); + // Get list of types from the context base implementation, ... + uno::Sequence aTypeList (AccessibleContextBase::getTypes()); + // ... get list of types from component base implementation, ... + uno::Sequence aComponentTypeList (AccessibleComponentBase::getTypes()); + // ... define local types, ... + const uno::Type aLangEventListenerType = + cppu::UnoType::get(); + const uno::Type aDocumentEventListenerType = + cppu::UnoType::get(); + const uno::Type aUnoTunnelType = + cppu::UnoType::get(); + + // ... and merge them all into one list. + sal_Int32 nTypeCount (aTypeList.getLength()), + nComponentTypeCount (aComponentTypeList.getLength()); + + aTypeList.realloc (nTypeCount + nComponentTypeCount + 3); + + std::copy(aComponentTypeList.begin(), aComponentTypeList.end(), + std::next(aTypeList.begin(), nTypeCount)); + + int i = nTypeCount + nComponentTypeCount; + + aTypeList[ i++ ] = aLangEventListenerType; + aTypeList[ i++ ] = aDocumentEventListenerType; + aTypeList[ i ] = aUnoTunnelType; + + return aTypeList; +} + +// 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 (maMutex); + + 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") + { + //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 (maMutex); + + // Make sure to send an event that this object loses the focus in the + // case that it has the focus. + ::utl::AccessibleStateSetHelper* pStateSet = + static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if (pStateSet != nullptr) + pStateSet->RemoveState (AccessibleStateType::FOCUSED); + + // Unregister from model. + if (mxShape.is() && maShapeTreeInfo.GetModelBroadcaster().is()) + maShapeTreeInfo.GetModelBroadcaster()->removeShapeEventListener(mxShape, + static_cast(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 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& xshape1, + const uno::Reference& xshape2 ) const + { + SdrObject* pObj1 = GetSdrObjectFromXShape(xshape1); + SdrObject* pObj2 = 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( 3 ); + aRet[0] = 0; + aRet[1] = 0; + aRet[2] = 0; + + css::uno::Reference xParent = getAccessibleParent(); + if (!xParent.is()) + { + return aRet; + } + SdrObject *pObj = 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 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::makeAny( 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 > 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 = 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::makeAny( 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 + + +namespace accessibility { + +AccessibleShapeInfo::AccessibleShapeInfo ( + const css::uno::Reference& rxShape, + const css::uno::Reference& rxParent, + IAccessibleParent* pChildrenManager) + : mxShape (rxShape), + mxParent (rxParent), + mpChildrenManager (pChildrenManager) +{ + // empty. +} + + +AccessibleShapeInfo::AccessibleShapeInfo ( + const css::uno::Reference& rxShape, + const css::uno::Reference& 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..edc7ef8a9 --- /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 +#include +#include + +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& rxDocumentWindow) +{ + if (mxDocumentWindow != rxDocumentWindow) + mxDocumentWindow = rxDocumentWindow; +} + +void AccessibleShapeTreeInfo::SetModelBroadcaster ( + const Reference& rxModelBroadcaster) +{ + mxModelBroadcaster = rxModelBroadcaster; +} + +void AccessibleShapeTreeInfo::SetSdrView (SdrView* pView) +{ + mpView = pView; +} + +void AccessibleShapeTreeInfo::SetController ( + const Reference& rxController) +{ + mxController = rxController; +} + +void AccessibleShapeTreeInfo::SetDevice(OutputDevice* 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 +#include "AccessibleTextEventQueue.hxx" + +#include +#include +#include + +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 +#include +#include + +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..9a61a3863 --- /dev/null +++ b/svx/source/accessibility/AccessibleTextHelper.cxx @@ -0,0 +1,1786 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// Project-local header + + +#include "AccessibleTextEventQueue.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../table/accessiblecell.hxx" +#include +#include +#include + +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 + { + ::osl::MutexGuard 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( const 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() + { + // 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; + + int 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 ::osl::Mutex maMutex; + + /// our current offset to the containing shape/cell (guarded by maMutex) + Point maOffset; + + /// client Id from AccessibleEventNotifier + int mnNotifierClientId; + }; + + 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( const VectorOfStates& rChildStates ) + { + maParaManager.SetAdditionalChildStates( 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 ) + { + if( bHaveFocus ) + { + if( mxFrontEnd.is() ) + { + AccessibleCell* pAccessibleCell = dynamic_cast< AccessibleCell* > ( mxFrontEnd.get() ); + if ( !pAccessibleCell ) + GotPropertyEvent( uno::makeAny(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::makeAny(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::makeAny(static_cast(-1)), + uno::makeAny(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(-1); + } + + maParaManager.FireEvent( aSelection.nEndPara, + aSelection.nEndPara+1, + AccessibleEventId::CARET_CHANGED, + uno::makeAny(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 sortedSelection( + makeSortedPair(::std::min( aSelection.nStartPara, nMaxValidParaIndex ), + ::std::min( aSelection.nEndPara, nMaxValidParaIndex ) ) ); + + // #108947# Sort last range before calling FireEvent + ::std::pair 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 (#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 (#i27299#) + if ( maLastSelection.HasRange() && + !aSelection.HasRange() ) + { + // selection was on, now is empty + maParaManager.FireEvent( sortedLastSelection.first, + sortedLastSelection.second+1, + nTextSelChgEventId ); + } + // use method (#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 + maParaManager.FireEvent( nPara, + nTextSelChgEventId ); + } + else + { + // check for changed selection on paragraph + 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 + { + ::osl::MutexGuard 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(); + + mnFirstVisibleChild = -1; + mnLastVisibleChild = -2; + + for( sal_Int32 nCurrPara=0; nCurrParagetBounds(); + 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 + return ::accessibility::AccessibleParaManager::WeakChild( rChild.first, aNewRect ); + } + } + + // identity transform + return rChild; + } + }; + + } + + void AccessibleTextHelper_Impl::UpdateBoundRect() + { + // send BOUNDRECT_CHANGED to affected children + AccessibleTextHelper_UpdateChildBounds aFunctor; + ::std::transform( maParaManager.begin(), maParaManager.end(), maParaManager.begin(), aFunctor ); + } + +#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::makeAny>(aHardRef.get()) ); + } + + 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 ) + { + // 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 ) + { + // determine hint type + const TextHint* pTextHint = dynamic_cast( pEvent ); + const SvxEditSourceHint* pEditSourceHint = dynamic_cast( pEvent ); + + if( !pEditSourceHint && pTextHint && + (pTextHint->GetId() == SfxHintId::TextParaInserted || + pTextHint->GetId() == SfxHintId::TextParaRemoved ) ) + { + 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( labs( 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::makeAny( 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().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::makeAny( 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; + } + + 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( &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( &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. + UpdateVisibleChildren(); + UpdateBoundRect(); + } + else if ( dynamic_cast( &rHint ) ) + { + // just check visibility + UpdateVisibleChildren(); + UpdateBoundRect(); + } + // 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( &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( &rHint ) ) + { + // EditEngine should emit TEXT_SELECTION_CHANGED events (#i27299#) + maEventQueue.Append( *pEditSourceHint ); + } + else if( const TextHint* pTextHint = dynamic_cast( &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() != -1 ) + { + try + { + // #106234# Unregister from EventNotifier + ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() ); + SAL_INFO("svx", "disposed ID: " << mnNotifierClientId ); + } + catch( const uno::Exception& ) {} + + mnNotifierClientId = -1; + } + + 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; + { + osl::MutexGuard 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(), 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 + { + // #102261# Call global queue for focus events + if( rEvent.EventId == AccessibleStateType::FOCUSED ) + vcl::unohelper::NotifyAccessibleStateEventGlobally( rEvent ); + + // #106234# Delegate to EventNotifier + ::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() != -1 ) + ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener ); + } + + void AccessibleTextHelper_Impl::removeAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) + { + if( getNotifierClientId() != -1 ) + { + 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 = -1; + ::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.IsInside( 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( const VectorOfStates& rChildStates ) + { + mpImpl->SetAdditionalChildStates( 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..88bf9bd8c --- /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 +#include "ChildrenManagerImpl.hxx" +#include + +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& rxParent, + const css::uno::Reference& rxShapeList, + const AccessibleShapeTreeInfo& rShapeTreeInfo, + AccessibleContextBase& rContext) + : mpImpl( + new ChildrenManagerImpl( + rxParent, rxShapeList, rShapeTreeInfo, rContext)) +{ + mpImpl->Init (); +} + + +ChildrenManager::~ChildrenManager() +{ + mpImpl->dispose(); + + // empty + SAL_INFO("svx", "~ChildrenManager"); +} + +long ChildrenManager::GetChildCount() const throw () +{ + return mpImpl->GetChildCount(); +} + +css::uno::Reference ChildrenManager::GetChild (long nIndex) +{ + return mpImpl->GetChild (nIndex); +} + +css::uno::Reference ChildrenManager::GetChildShape(long nIndex) +{ + return mpImpl->GetChildShape(nIndex); +} + +void ChildrenManager::Update (bool bCreateNewObjectsOnDemand) +{ + mpImpl->Update (bCreateNewObjectsOnDemand); +} + +void ChildrenManager::SetShapeList (const css::uno::Reference& xShapeList) +{ + mpImpl->SetShapeList (xShapeList); +} + +void ChildrenManager::AddAccessibleShape (css::uno::Reference 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..dbfeb7ce4 --- /dev/null +++ b/svx/source/accessibility/ChildrenManagerImpl.cxx @@ -0,0 +1,1040 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "ChildrenManagerImpl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& rxParent, + const uno::Reference& rxShapeList, + const AccessibleShapeTreeInfo& rShapeTreeInfo, + AccessibleContextBase& rContext) + : ::cppu::WeakComponentImplHelper< + css::document::XEventListener, + css::view::XSelectionChangeListener>(maMutex), + mxShapeList (rxShapeList), + mxParent (rxParent), + maShapeTreeInfo (rShapeTreeInfo), + mrContext (rContext), + mpFocusedShape(nullptr) +{ +} + + +ChildrenManagerImpl::~ChildrenManagerImpl() +{ + DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose, + "~AccessibleDrawDocumentView: object has not been disposed"); +} + + +void ChildrenManagerImpl::Init() +{ + // Register as view::XSelectionChangeListener. + Reference xController(maShapeTreeInfo.GetController()); + Reference xSelectionSupplier ( + xController, uno::UNO_QUERY); + if (xSelectionSupplier.is()) + { + xController->addEventListener( + static_cast(this)); + + xSelectionSupplier->addSelectionChangeListener ( + static_cast(this)); + } + + // Register at model as document::XEventListener. + if (maShapeTreeInfo.GetModelBroadcaster().is()) + maShapeTreeInfo.GetModelBroadcaster()->addEventListener ( + static_cast(this)); +} + + +long ChildrenManagerImpl::GetChildCount() const throw () +{ + return maVisibleChildren.size(); +} + + +css::uno::Reference ChildrenManagerImpl::GetChildShape(long nIndex) +{ + uno::Reference 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 + ChildrenManagerImpl::GetChild (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 + 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 pShape( + ShapeTypeHandler::Instance().CreateAccessibleObject ( + aShapeInfo, + maShapeTreeInfo)); + rChildDescriptor.mxAccessibleShape.set( + static_cast(pShape.get()), + uno::UNO_QUERY); + 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) + { + //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 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()) + { + sal_Int32 nShapeCount = mxShapeList->getCount(); + raDescriptorList.reserve( nShapeCount ); + awt::Point aPos; + awt::Size aSize; + tools::Rectangle aBoundingBox; + uno::Reference xShape; + for (sal_Int32 i=0; igetByIndex(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.IsOver (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::makeAny(rChild.mxAccessibleShape), + uno::Any()); + } + ++nPos; + } +} + + +void ChildrenManagerImpl::AddShape (const Reference& rxShape) +{ + if (rxShape.is()) + { + 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 xChild (rxShape, uno::UNO_QUERY); + if (xChild.is()) + { + Reference xParent (xChild->getParent(), uno::UNO_QUERY); + if (xParent == mxShapeList) + if (aBoundingBox.IsOver (aVisibleArea)) + { + // 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& rxShape) +{ + if (rxShape.is()) + { + SolarMutexGuard g; + + // Search shape in list of visible children. + ChildDescriptorListType::iterator I ( + ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(), + ChildDescriptor (rxShape))); + if (I != maVisibleChildren.end()) + { + // Remove descriptor from that list. + Reference 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& xShapeList) +{ + mxShapeList = xShapeList; +} + + +void ChildrenManagerImpl::AddAccessibleShape (css::uno::Reference 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 xCurrentBroadcaster; + Reference xCurrentController; + Reference 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(this)); + + // Unregister at old broadcaster. + if (xCurrentBroadcaster.is()) + xCurrentBroadcaster->removeEventListener ( + static_cast(this)); + } + + // Move registration to new selection supplier. + Reference xNewController(maShapeTreeInfo.GetController()); + Reference xNewSelectionSupplier ( + xNewController, uno::UNO_QUERY); + if (xNewSelectionSupplier != xCurrentSelectionSupplier) + { + // Register at new broadcaster. + if (xNewSelectionSupplier.is()) + { + xNewController->addEventListener( + static_cast(this)); + + xNewSelectionSupplier->addSelectionChangeListener ( + static_cast(this)); + } + + // Unregister at old broadcaster. + if (xCurrentSelectionSupplier.is()) + { + xCurrentSelectionSupplier->removeSelectionChangeListener ( + static_cast(this)); + + xCurrentController->removeEventListener( + static_cast(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 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(rEventObject.Source, uno::UNO_QUERY)); + else if (rEventObject.EventName == "ShapeRemoved") + RemoveShape (Reference(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 xController(maShapeTreeInfo.GetController()); + // Remove from broadcasters. + try + { + Reference xSelectionSupplier ( + xController, uno::UNO_QUERY); + if (xSelectionSupplier.is()) + { + xSelectionSupplier->removeSelectionChangeListener ( + static_cast(this)); + } + } + catch( uno::RuntimeException&) + {} + + try + { + if (xController.is()) + xController->removeEventListener( + static_cast(this)); + } + catch( uno::RuntimeException&) + {} + + maShapeTreeInfo.SetController (nullptr); + + try + { + // Remove from broadcaster. + if (maShapeTreeInfo.GetModelBroadcaster().is()) + maShapeTreeInfo.GetModelBroadcaster()->removeEventListener ( + static_cast(this)); + maShapeTreeInfo.SetModelBroadcaster (nullptr); + } + catch( uno::RuntimeException& ) + {} + + ClearAccessibleShapeList (); + SetShapeList (nullptr); +} + + +void SAL_CALL ChildrenManagerImpl::disposing() +{ + impl_dispose(); +} + +// IAccessibleViewForwarderListener +void ChildrenManagerImpl::ViewForwarderChanged() +{ + Update(false); +} + +// IAccessibleParent +bool ChildrenManagerImpl::ReplaceChild ( + AccessibleShape* pCurrentChild, + const css::uno::Reference< css::drawing::XShape >& _rxShape, + const 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::makeAny (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 pNewChild(ShapeTypeHandler::Instance().CreateAccessibleObject ( + aShapeInfo, + _rShapeTreeInfo + )); + if ( pNewChild.is() ) + pNewChild->Init(); + + I->mxAccessibleShape = pNewChild.get(); + mrContext.CommitChange ( + AccessibleEventId::CHILD, + uno::makeAny (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;indexGetXShape()) == DRAWING_CONTROL) + { + auto* pCtlAccShape = static_cast<::accessibility::AccessibleControlShape*>(pAccShape); + if (pCtlAccShape->GetControlModel() == pSet) + return pCtlAccShape; + } + } + return nullptr; +} +uno::Reference + ChildrenManagerImpl::GetAccessibleCaption (const uno::Reference& 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 (); +} + +/** Update the SELECTED and the FOCUSED 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() +{ + Reference xController(maShapeTreeInfo.GetController()); + Reference xSelectionSupplier ( + xController, uno::UNO_QUERY); + + // Try to cast the selection both to a multi selection and to a single + // selection. + Reference xSelectedShapeAccess; + Reference xSelectedShape; + if (xSelectionSupplier.is()) + { + xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY); + xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY); + } + + // 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; + 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 (xSelectedShapeAccess.is()) + { + sal_Int32 nCount=xSelectedShapeAccess->getCount(); + for (sal_Int32 i=0; igetByIndex(i) == rChild.mxShape) + { + bShapeIsSelected = true; + // In a multi-selection no shape has the focus. + if (nCount == 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& xShape) +{ + Reference xComponent (xShape, uno::UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener ( + static_cast(this)); +} + + +void ChildrenManagerImpl::UnregisterAsDisposeListener ( + const Reference& xShape) +{ + Reference xComponent (xShape, uno::UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener ( + static_cast(this)); +} + +// AccessibleChildDescriptor +ChildDescriptor::ChildDescriptor (const Reference& xShape) + : mxShape (xShape), + mbCreateEventPending (true) +{ + // Empty. +} + + +ChildDescriptor::ChildDescriptor (const Reference& rxAccessibleShape) + : mxAccessibleShape (rxAccessibleShape), + mbCreateEventPending (true) +{ + // Make sure that the accessible object has the VISIBLE + // state set. + AccessibleShape* pAccessibleShape = GetAccessibleShape(); + pAccessibleShape->SetState (AccessibleStateType::VISIBLE); +} + +AccessibleShape* ChildDescriptor::GetAccessibleShape() const +{ + return static_cast (mxAccessibleShape.get()); +} + +void ChildDescriptor::setIndexAtAccessibleShape(sal_Int32 _nIndex) +{ + AccessibleShape* pShape = GetAccessibleShape(); + if ( pShape ) + pShape->setIndexInParent(_nIndex); +} + + +void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase& rParent) +{ + if (mxAccessibleShape.is()) + { + // 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 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..e09dec4b7 --- /dev/null +++ b/svx/source/accessibility/ChildrenManagerImpl.hxx @@ -0,0 +1,495 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace accessibility { + +class AccessibleShape; + +class ChildDescriptor; // See below for declaration. +typedef ::std::vector ChildDescriptorListType; + +// Re-using MutexOwner class defined in AccessibleContextBase.hxx + +/** This class contains the actual implementation of the children manager. + +

It maintains a set of visible accessible shapes in + maVisibleChildren. 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 + maShapeList. Accessible objects for these shapes are + created on demand. The list can be replaced by calls to the + SetShapeList method. The second source is a list of + already accessible objects. It can be modified by calls to the + AddAccessibleShape and + ClearAccessibleShapeList methods.

+ +

Each call of the Update method leads to a + re-calculation of the visible shapes which then can be queried with the + GetChildCount and GetChild methods. + Events are send informing all listeners about the removed shapes which are + not visible anymore and about the added shapes.

+ +

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 ViewForwarderChanged.

+ +

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.

+ + @see ChildrenManager +*/ +class ChildrenManagerImpl final + : public MutexOwner, + public cppu::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& rxParent, + const css::uno::Reference& 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. + */ + long GetChildCount() const throw (); + + /// @throws css::uno::RuntimeException + /// @throws css::lang::IndexOutOfBoundsException + css::uno::Reference GetChildShape(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 + GetChild (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 + 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 then accessible objects associated with the visible + shapes are created only when asked for. No event is sent on + creation. If 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 AddAccessibleShape 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& 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 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 + and resetting the states. + */ + void UpdateSelection(); + + /** Return whether one of the shapes managed by this object has + currently the focus. + @return + Returns when there is a shape that has the focus and + when there is no such shape. + */ + bool HasFocus() const; + + /** When there is a shape that currently has the focus, + i.e. HasFocus() returns 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 VISIBLE_AREA leads to a call to + the Update which creates accessible objects of + new shapes immediately. Other change types are passed to the + visible accessible children without calling + Update. + @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 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 + GetAccessibleCaption (const css::uno::Reference& xShape) override; + +private: + /** This list holds the descriptors of all currently visible shapes and + associated accessible object. + +

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).

+ +

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.

+ */ + ChildDescriptorListType maVisibleChildren; + + /** The original list of UNO shapes. The visible shapes are inserted + into the list of visible children + maVisibleChildren. + */ + css::uno::Reference 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 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 SAL_CALL disposing() 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 Update method. + */ + + /** Create a list of visible shapes from the list of UNO shapes + maShapeList 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 Update() + when only a single shape has been added. + */ + void AddShape (const css::uno::Reference& xShape); + + /** Remove a single shape. Update all relevant data structures + accordingly. Use this method instead of Update() + when only a single shape has been removed. + */ + void RemoveShape (const css::uno::Reference& 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& 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& xShape); +}; + + +/** A child descriptor holds a reference to a UNO shape and the + corresponding accessible object. There are two use cases: +
  1. The accessible object is only created on demand and is then + initially empty.
  2. +
  3. There is no UNO shape. The accessible object is given as argument + to the constructor.
  4. +
+ In both cases the child descriptor assumes ownership over the accessible + object. +*/ +class ChildDescriptor +{ +public: + /** Reference to a (partially) visible shape. + */ + css::uno::Reference 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 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& xShape); + + /** Create a new descriptor for the specified shape with empty reference + to the original shape. + */ + explicit ChildDescriptor (const css::uno::Reference& 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..1716f999f --- /dev/null +++ b/svx/source/accessibility/DescriptionGenerator.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 +#include +#include +#include +#include +#include +#include + +// Includes for string resources. +#include +#include + +#include "lookupcolorname.hxx" + +using namespace ::com::sun::star; + + +namespace accessibility { + + +DescriptionGenerator::DescriptionGenerator ( + const uno::Reference& xShape) + : mxShape (xShape), + mxSet (mxShape, uno::UNO_QUERY), + mbIsFirstProperty (true) +{ +} + + +DescriptionGenerator::~DescriptionGenerator() +{ +} + + +void DescriptionGenerator::Initialize(const char* 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 (const OUString& sPrefix) +{ + msDescription = sPrefix; + if (mxSet.is()) + { + { + 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 xStyle (aValue, uno::UNO_QUERY); + if (xStyle.is()) + msDescription.append (xStyle->getName()); + } + else + msDescription.append (""); + } + catch (const css::beans::UnknownPropertyException &) + { + msDescription.append (""); + } + } +} + + +OUString DescriptionGenerator::operator() () +{ + msDescription.append('.'); + return msDescription.makeStringAndClear(); +} + + +void DescriptionGenerator::AddProperty (const OUString& sPropertyName, + PropertyType aType) +{ + uno::Reference xState (mxShape, uno::UNO_QUERY); + if (xState.is() + && xState->getPropertyState(sPropertyName)!=beans::PropertyState_DEFAULT_VALUE) + if (mxSet.is()) + { + // 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 (const OUString& 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 + { + + 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 (""); + } +} + + +void DescriptionGenerator::AddInteger (const OUString& sPropertyName) +{ + msDescription.append('='); + + try + { + if (mxSet.is()) + { + uno::Any aValue = mxSet->getPropertyValue (sPropertyName); + long nValue = 0; + aValue >>= nValue; + msDescription.append (nValue); + } + } + catch (const css::beans::UnknownPropertyException &) + { + msDescription.append (""); + } +} + +} // 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..8d0c4dfc0 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// 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.SetDevice(&mpControl->GetDrawingArea()->get_ref_device()); + 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 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(pObj)->getUnoShape() ) ); + + css::uno::Reference xParent(getAccessibleParent()); + AccessibleShapeInfo aShapeInfo (xShape,xParent); + // Create accessible object that corresponds to the descriptor's shape. + rtl::Reference 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, makeAny( xAccessibleShape ), makeAny( Reference() ) ); + } + } + + 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 ); + 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 xParentContext(xParent->getAccessibleContext()); + css::uno::Reference 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(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 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(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; + + 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 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()) + { + ::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(nColor); +} + +sal_Int32 SAL_CALL SvxGraphCtrlAccessibleContext::getBackground() +{ + Color nColor = Application::GetSettings().GetStyleSettings().GetWindowColor(); + return static_cast(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_CALL SvxGraphCtrlAccessibleContext::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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(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(nIndex))->GetMarkedSdrObj(); + if( pObj ) + xAccessible = getAccessible( pObj ); + + return xAccessible; +} + + +void SAL_CALL SvxGraphCtrlAccessibleContext::deselectAccessibleChild( sal_Int32 nIndex ) +{ + ::SolarMutexGuard aGuard; + + checkChildIndexOnSelection( nIndex ); + + if( mpView ) + { + const SdrMarkList& rList = mpView->GetMarkedObjectList(); + + SdrObject* pObj = getSdrObject( nIndex ); + if( pObj ) + { + 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( 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 pAcc(rEntry.second.get()); + 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( &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 pShape((*iter).second); + + if( pShape.is() ) + pShape->CommitChange( AccessibleEventId::VISIBLE_DATA_CHANGED, uno::Any(), uno::Any() ); + } + } + break; + + case SdrHintKind::ObjectInserted: + CommitChange( AccessibleEventId::CHILD, makeAny( getAccessible( pSdrHint->GetObject() ) ) , uno::Any()); + break; + case SdrHintKind::ObjectRemoved: + CommitChange( AccessibleEventId::CHILD, uno::Any(), makeAny( 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..133ce38be --- /dev/null +++ b/svx/source/accessibility/ShapeTypeHandler.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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +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 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& 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 + ShapeTypeHandler::CreateAccessibleObject ( + const AccessibleShapeInfo& rShapeInfo, + const AccessibleShapeTreeInfo& rShapeTreeInfo) const +{ + ShapeTypeId nSlotId (GetSlotId (rShapeInfo.mxShape)); + rtl::Reference 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; isecond; + else + return 0; +} + + +// Extract the given shape's service name and forward request to appropriate +// method. +long ShapeTypeHandler::GetSlotId (const uno::Reference& 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& rxShape) +{ + const char* 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 (SvxShape* pShape = comphelper::getUnoTunnelImplementation(rxShape)) + { + if (auto pCustomShape = dynamic_cast(pShape->GetSdrObject())) + { + if (pCustomShape->IsTextPath()) + pResourceId = STR_ObjNameSingulFONTWORK; + else + { + pResourceId = nullptr; + sName = pCustomShape->GetCustomShapeName(); + } + } + } + break; + case DRAWING_TEXT: + pResourceId = STR_ObjNameSingulTEXT; + break; + default: + pResourceId = nullptr; + 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..5ca2804b5 --- /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 +#include +#include +#include +#include +#include +#include + +namespace accessibility { + +static 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 + SvxShapeTypes 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..3960b8a72 --- /dev/null +++ b/svx/source/accessibility/charmapacc.cxx @@ -0,0 +1,588 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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.get(); +} + +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(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(); +} + +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 ); + + ::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( + 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 ); + + Sequence< sal_Int32 > aSel(1); + aSel[0] = SvxShowCharSet::GetRowPos(m_pParent->GetSelectIndexId()); + return aSel; +} + +Sequence< sal_Int32 > SAL_CALL SvxShowCharSetAcc::getSelectedAccessibleColumns( ) +{ + OExternalLockGuard aGuard( this ); + + Sequence< sal_Int32 > aSel(1); + aSel[0] = SvxShowCharSet::GetColumnPos(m_pParent->GetSelectIndexId()); + return aSel; +} + +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(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(nChildIndex)); +} + +sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleColumn( sal_Int32 nChildIndex ) +{ + OExternalLockGuard aGuard( this ); + + return SvxShowCharSet::GetColumnPos(sal::static_int_cast(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); + sal_Int32 nStrIndex = 0; + const sal_UCS4 c = aCharStr.iterateCodePoints( &nStrIndex ); + 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(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 ); + + ::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(rStyleSettings.GetDialogTextColor()); +} + +sal_Int32 SAL_CALL SvxShowCharSetAcc::getBackground( ) +{ + OExternalLockGuard aGuard( this ); + + //see SvxShowCharSet::InitSettings + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + return static_cast(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..58d882026 --- /dev/null +++ b/svx/source/accessibility/lookupcolorname.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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lookupcolorname.hxx" +#include + +namespace { + +class ColorNameMap { +public: + ColorNameMap(); + ColorNameMap(const ColorNameMap&) = delete; + ColorNameMap& operator=(const ColorNameMap&) = delete; + + OUString lookUp(long color) const; + +private: + typedef std::unordered_map< 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()) + 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); + 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(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); +} + +struct theColorNameMap: public rtl::Static< ColorNameMap, theColorNameMap > {}; + +} + +namespace accessibility { + +OUString lookUpColorName(long color) { + return theColorNameMap::get().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..4c4a672b2 --- /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 + +#include + +namespace accessibility { + +/** This is a color name lookup targeted to be used by the accessibility + DescriptionGenerator class. It encapsulates a + com.sun.star.drawing.ColorTable and provides an inverse look + up of color names for given numerical color descriptions (the RGB values + encoded as an integer). + +

The implementation uses as singleton so that the + com.sun.star.drawing.ColorTable 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.

+ + @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(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..e966698a2 --- /dev/null +++ b/svx/source/accessibility/svxpixelctlaccessiblecontext.cxx @@ -0,0 +1,469 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +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(); +} + +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(); +} + +uno::Reference< XAccessibleStateSet > SvxPixelCtlAccessible::getAccessibleStateSet( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + utl::AccessibleStateSetHelper* pStateSetHelper = new utl::AccessibleStateSetHelper; + uno::Reference< XAccessibleStateSet > xRet = pStateSetHelper; + + 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 xRet; +} + +uno::Reference SAL_CALL SvxPixelCtlAccessible::getAccessibleAtPoint ( + const awt::Point& rPoint) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XAccessible > xRet; + + if (mpPixelCtl) + { + 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; + + 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(long nIndex,bool bSelect ,bool bCheck) +{ + DBG_ASSERT( !(!bSelect && !bCheck),"" );//non is false + + SvxPixelCtlAccessibleChild *pChild= nullptr; + + if (m_xCurChild.is()) + { + pChild= static_cast(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 xNewChild =CreateChild(nIndex, mpPixelCtl->IndexToPoint(nIndex)); + SvxPixelCtlAccessibleChild *pNewChild= static_cast(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 SvxPixelCtlAccessible::CreateChild (long nIndex,Point mPoint) +{ + bool bPixelColorOrBG = mpPixelCtl->GetBitmapPixel(sal_uInt16(nIndex)) != 0; + Size size(mpPixelCtl->GetWidth() / SvxPixelCtl::GetLineCount(), mpPixelCtl->GetHeight() / SvxPixelCtl::GetLineCount()); + uno::Reference 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& rxParent, + 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.get(); +} + +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 SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleRelationSet() +{ + return uno::Reference< XAccessibleRelationSet >(); +} + +uno::Reference< XAccessibleStateSet > SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleStateSet() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + 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 ); + + 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..1d767be13 --- /dev/null +++ b/svx/source/accessibility/svxrectctaccessiblecontext.cxx @@ -0,0 +1,643 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + { + const char* pResIdName; + const char* pResIdDescr; + RectPoint ePoint; + }; +} + + +static const ChildIndexToPointData* IndexToPoint( 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 long PointToIndex( RectPoint ePoint ) +{ + long nRet( static_cast(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(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; + + 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 ].get()); + 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 ) ); + + 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(); +} + +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(); +} + +Reference< XAccessibleStateSet > SAL_CALL SvxRectCtlAccessibleContext::getAccessibleStateSet() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + 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( long nIndex ) +{ + if( nIndex < 0 || nIndex >= getAccessibleChildCount() ) + throw lang::IndexOutOfBoundsException(); +} + +void SvxRectCtlAccessibleContext::FireChildFocus( RectPoint eButton ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + long nNew = PointToIndex( eButton ); + 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( long nNew ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if( nNew != mnSelectedChild ) + { + long nNumOfChildren = getAccessibleChildCount(); + if( nNew < nNumOfChildren ) + { // valid index + SvxRectCtlChildAccessibleContext* pChild; + if( mnSelectedChild != NOCHILDSELECTED ) + { // deselect old selected child if one is selected + 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& rxParent, + const OUString& rName, + const OUString& rDescription, + const tools::Rectangle& rBoundingBox, + 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 SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleRelationSet() +{ + utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper; + uno::Reference< css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper; + if( mxParent.is() ) + { + uno::Sequence< uno::Reference< uno::XInterface > > aSequence { mxParent }; + pRelationSetHelper->AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) ); + + } + + return xSet; +} + +Reference< XAccessibleStateSet > SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleStateSet() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + 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; +} + + +// 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 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 ) + { + 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..b6e1387ab --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +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 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 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 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(&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) + { + SdrGrafObj *const pNewObj(static_cast(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..c4755ff10 --- /dev/null +++ b/svx/source/core/graphichelper.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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->getVectorGraphicDataArrayLength()) + { + switch (rVectorGraphicDataPtr->getVectorGraphicDataType()) + { + 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; + default: + break; + } + rExtension = aExtension; +} + +namespace { + + +bool lcl_ExecuteFilterDialog( const Sequence< PropertyValue >& rPropsForDialog, + Sequence< PropertyValue >& rFilterData ) +{ + bool bStatus = false; + try + { + const OUString aServiceName("com.sun.star.svtools.SvFilterOptionsDialog"); + Reference< XExecutableDialog > xFilterDialog( + comphelper::getProcessServiceFactory()->createInstance( aServiceName ), 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) +{ + SvtPathOptions aPathOpt; + OUString sGraphicsPath( aPathOpt.GetGraphicPath() ); + + FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent); + Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker(); + + INetURLObject aPath; + aPath.SetSmartURL( sGraphicsPath ); + + // fish out the graphic's name + + aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_EXPORT_GRAPHIC_TITLE)); + aDialogHelper.SetDisplayDirectory( aPath.GetMainURL(INetURLObject::DecodeMechanism::ToIUri) ); + 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] ); + // remember used path - please don't optimize away! + aPath.SetSmartURL( sPath); + sGraphicsPath = aPath.GetPath(); + + 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 = aGraphic.GetXGraphic(); + + OUString aExportFilter = rGraphicFilter.GetExportInternalFilterName(nFilter); + + Sequence< PropertyValue > aPropsForDialog(2); + aPropsForDialog[0].Name = "Graphic"; + aPropsForDialog[0].Value <<= xGraphic; + aPropsForDialog[1].Name = "FilterName"; + aPropsForDialog[1].Value <<= 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::SaveShapeAsGraphic(weld::Window* pParent, const Reference< drawing::XShape >& xShape) +{ + try + { + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference< XPropertySet > xShapeSet( xShape, UNO_QUERY_THROW ); + + SvtPathOptions aPathOpt; + const OUString& sGraphicPath( aPathOpt.GetGraphicPath() ); + + FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent); + Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker(); + + aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_SAVEAS_IMAGE) ); + + INetURLObject aPath; + aPath.SetSmartURL( sGraphicPath ); + xFilePicker->setDisplayDirectory( aPath.GetMainURL(INetURLObject::DecodeMechanism::ToIUri) ); + + // populate filter dialog filter list and select default filter to match graphic mime type + + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + const OUString aDefaultMimeType("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()] ); + + Reference< XInputStream > xGraphStream; + + if( xGraphStream.is() ) + { + Reference xFileAccess = SimpleFileAccess::create( xContext ); + xFileAccess->writeFile( sPath, xGraphStream ); + } + else + { + Reference xGraphicExporter = css::drawing::GraphicExportFilter::create( xContext ); + + Sequence aDescriptor( 2 ); + aDescriptor[0].Name = "MediaType"; + aDescriptor[0].Value <<= aExportMimeType; + aDescriptor[1].Name = "URL"; + aDescriptor[1].Value <<= sPath; + + Reference< XComponent > xSourceDocument( xShape, UNO_QUERY_THROW ); + xGraphicExporter->setSourceDocument( xSourceDocument ); + xGraphicExporter->filter( aDescriptor ); + } + } + } + catch( Exception& ) + { + } +} + +short GraphicHelper::HasToSaveTransformedImage(weld::Widget* pWin) +{ + OUString aMsg(SvxResId(RID_SVXSTR_SAVE_MODIFIED_IMAGE)); + std::unique_ptr 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..89360b62f --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShape2d.cxx @@ -0,0 +1,3040 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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(nValue); + sal_Int32 nNewValue = nValue; + + // check if this is a special point + if ( ( nDat >> 16 ) == 0x8000 ) + { + nNewValue = static_cast(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 + const Any* pAny = const_cast(rGeometryItem).GetPropertyValueByName( "AdjustmentValues" ); + if ( pAny ) + *pAny >>= seqAdjustmentValues; + + + // Coordsize + const Any* pViewBox = const_cast(rGeometryItem).GetPropertyValueByName( "ViewBox" ); + css::awt::Rectangle aViewBox; + if ( pViewBox && (*pViewBox >>= aViewBox ) ) + { + nCoordLeft = aViewBox.X; + nCoordTop = aViewBox.Y; + nCoordWidthG = labs( aViewBox.Width ); + nCoordHeightG = labs( aViewBox.Height); + } + const OUString sPath( "Path" ); + + + // Path/Coordinates + pAny = const_cast(rGeometryItem).GetPropertyValueByName( sPath, "Coordinates" ); + if ( pAny ) + *pAny >>= seqCoordinates; + + + // Path/GluePoints + pAny = const_cast(rGeometryItem).GetPropertyValueByName( sPath, "GluePoints" ); + if ( pAny ) + *pAny >>= seqGluePoints; + + + // Path/Segments + pAny = const_cast(rGeometryItem).GetPropertyValueByName( sPath, "Segments" ); + if ( pAny ) + *pAny >>= seqSegments; + + + // Path/SubViewSize + pAny = const_cast(rGeometryItem).GetPropertyValueByName( sPath, "SubViewSize" ); + if ( pAny ) + *pAny >>= seqSubViewSize; + + + // Path/StretchX + pAny = const_cast(rGeometryItem).GetPropertyValueByName( sPath, "StretchX" ); + if ( pAny ) + { + sal_Int32 nStretchX = 0; + if ( *pAny >>= nStretchX ) + nXRef = nStretchX; + } + + + // Path/StretchY + pAny = const_cast(rGeometryItem).GetPropertyValueByName( sPath, "StretchY" ); + if ( pAny ) + { + sal_Int32 nStretchY = 0; + if ( *pAny >>= nStretchY ) + nYRef = nStretchY; + } + + + // Path/TextFrames + pAny = const_cast(rGeometryItem).GetPropertyValueByName( sPath, "TextFrames" ); + if ( pAny ) + *pAny >>= seqTextFrames; + + + // Equations + pAny = const_cast(rGeometryItem).GetPropertyValueByName( "Equations" ); + if ( pAny ) + *pAny >>= seqEquations; + + + // Handles + pAny = const_cast(rGeometryItem).GetPropertyValueByName( "Handles" ); + 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(aLogicRect.GetWidth()) / static_cast(nCoordWidth); + fYScale = nCoordHeight == 0 ? 0.0 : static_cast(aLogicRect.GetHeight()) / static_cast(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(aLogicRect.GetWidth()) / static_cast(nWidth); + else + fXScale = 1.0; + } + if ( nCoordHeight == 0 ) + { + if ( nHeight ) + fYScale = static_cast(aLogicRect.GetHeight()) / static_cast(nHeight); + else + fYScale = 1.0; + } + } + if ( static_cast(nXRef) != 0x80000000 && aLogicRect.GetHeight() ) + { + fXRatio = static_cast(aLogicRect.GetWidth()) / static_cast(aLogicRect.GetHeight()); + if ( fXRatio > 1 ) + fXScale /= fXRatio; + else + fXRatio = 1.0; + } + else + fXRatio = 1.0; + if ( static_cast(nYRef) != 0x80000000 && aLogicRect.GetWidth() ) + { + fYRatio = static_cast(aLogicRect.GetHeight()) / static_cast(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 )); + const Any* pAny = rGeometryItem.GetPropertyValueByName( "Type" ); + if ( pAny ) { + *pAny >>= sShapeType; + bOOXMLShape = sShapeType.startsWith("ooxml-"); + SAL_INFO("svx", "shape type: " << sShapeType << " " << bOOXMLShape); + } + eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType ); + + pAny = rGeometryItem.GetPropertyValueByName( "MirroredX" ); + if ( pAny ) + *pAny >>= bFlipH; + pAny = rGeometryItem.GetPropertyValueByName( "MirroredY" ); + if ( pAny ) + *pAny >>= bFlipV; + + nRotateAngle = static_cast(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 : + { + if( sShapeType.getLength() > 4 && + sShapeType.match( "col-" )) + { + nColorData = sShapeType.copy( 4 ).toUInt32( 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 ) + { + 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 = F_PI; break; + case ExpressionFunct::EnumLeft : fRet = static_cast(nCoordLeft); break; + case ExpressionFunct::EnumTop : fRet = static_cast(nCoordTop); break; + case ExpressionFunct::EnumRight : fRet = static_cast(nCoordLeft + nCoordWidth) * fXRatio; break; + case ExpressionFunct::EnumBottom : fRet = static_cast(nCoordTop + 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(nNumber); + } + } + return fNumber; +} +double EnhancedCustomShape2d::GetEquationValueAsDouble( const sal_Int32 nIndex ) const +{ + double fNumber = 0.0; + static sal_uInt32 nLevel = 0; + if ( nIndex < static_cast(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(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 + seqAdjustmentValues[ nIndex ].Value <<= rValue; + seqAdjustmentValues[ 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(aPoint.getX()), static_cast(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(static_cast< sal_Int32 >( std::clamp(rFillColor.GetRed() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )), + static_cast(static_cast< sal_Int32 >( std::clamp(rFillColor.GetGreen() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )), + static_cast(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(static_cast< sal_Int32 >( std::clamp(rFillColor.GetRed() * (1.0+dBrightness), 0.0, 255.0) )), + static_cast(static_cast< sal_Int32 >( std::clamp(rFillColor.GetGreen() * (1.0+dBrightness), 0.0, 255.0) )), + static_cast(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(static_cast< sal_Int32 >( std::clamp(aHSVColor.getRed(),0.0,1.0) * 255.0 + 0.5 )), + static_cast(static_cast< sal_Int32 >( std::clamp(aHSVColor.getGreen(),0.0,1.0) * 255.0 + 0.5 )), + static_cast(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.nTan; + if (bFlipV != bFlipH) + nTan = -nTan; + ShearPoint( rReturnPosition, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), nTan ); + } + if ( nRotateAngle ) + { + double a = nRotateAngle * F_PI18000; + 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(const OUString& 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 == "ooxml-bentArrow" && nHandleIndex == 2) || (rShapeType == "ooxml-chevron") + || (rShapeType == "ooxml-curvedRightArrow") || (rShapeType == "ooxml-foldedCorner") + || (rShapeType == "ooxml-homePlate") || (rShapeType == "ooxml-notchedRightArrow") + || (rShapeType == "ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 1) + || (rShapeType == "ooxml-rightArrow") + || (rShapeType == "ooxml-rightArrowCallout" && nHandleIndex == 2) + || (rShapeType == "ooxml-round1Rect") + || (rShapeType == "ooxml-round2DiagRect" && nHandleIndex == 1) + || (rShapeType == "ooxml-round2SameRect" && nHandleIndex == 0) + || (rShapeType == "ooxml-snip1Rect") + || (rShapeType == "ooxml-snip2DiagRect" && nHandleIndex == 1) + || (rShapeType == "ooxml-snip2SameRect" && nHandleIndex == 0) + || (rShapeType == "ooxml-snipRoundRect" && nHandleIndex == 1) + || (rShapeType == "ooxml-swooshArrow") || (rShapeType == "ooxml-stripedRightArrow")) + return (fW - fX) / std::min(fW, fH) * 100000.0; + + // pattern x / ss * 100000 or (x - l) / ss * 100000 + if ((rShapeType == "ooxml-bentArrow" && nHandleIndex == 0) + || (rShapeType == "ooxml-bentArrow" && nHandleIndex == 3) || (rShapeType == "ooxml-corner") + || (rShapeType == "ooxml-curvedDownArrow") || (rShapeType == "ooxml-curvedLeftArrow") + || (rShapeType == "ooxml-curvedUpArrow") || (rShapeType == "ooxml-leftArrow") + || (rShapeType == "ooxml-leftArrowCallout" && nHandleIndex == 2) + || (rShapeType == "ooxml-leftRightArrow") + || (rShapeType == "ooxml-leftRightArrowCallout" && nHandleIndex == 2) + || (rShapeType == "ooxml-leftRightRibbon") + || (rShapeType == "ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 0) + || (rShapeType == "ooxml-parallelogram") + || (rShapeType == "ooxml-round2DiagRect" && nHandleIndex == 0) + || (rShapeType == "ooxml-round2SameRect" && nHandleIndex == 1) + || (rShapeType == "ooxml-roundRect") + || (rShapeType == "ooxml-snip2DiagRect" && nHandleIndex == 0) + || (rShapeType == "ooxml-snip2SameRect" && nHandleIndex == 1) + || (rShapeType == "ooxml-snipRoundRect" && nHandleIndex == 0) + || (rShapeType == "ooxml-uturnArrow" && nHandleIndex == 0) + || (rShapeType == "ooxml-uturnArrow" && nHandleIndex == 3)) + return fX / std::min(fW, fH) * 100000.0; + + // pattern (hc - x) / ss * 200000 + if ((rShapeType == "ooxml-downArrowCallout" && nHandleIndex == 0) + || (rShapeType == "ooxml-leftRightUpArrow" && nHandleIndex == 0) + || (rShapeType == "ooxml-quadArrow" && nHandleIndex == 0) + || (rShapeType == "ooxml-quadArrowCallout" && nHandleIndex == 0) + || (rShapeType == "ooxml-upArrowCallout" && nHandleIndex == 0) + || (rShapeType == "ooxml-upDownArrowCallout" && nHandleIndex == 0)) + return (fW / 2.0 - fX) / std::min(fW, fH) * 200000.0; + + // pattern (hc - x) / ss * 100000 + if ((rShapeType == "ooxml-downArrowCallout" && nHandleIndex == 1) + || (rShapeType == "ooxml-leftRightUpArrow" && nHandleIndex == 1) + || (rShapeType == "ooxml-quadArrow" && nHandleIndex == 1) + || (rShapeType == "ooxml-quadArrowCallout" && nHandleIndex == 1) + || (rShapeType == "ooxml-upArrowCallout" && nHandleIndex == 1) + || (rShapeType == "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 == "ooxml-bentUpArrow") || (rShapeType == "ooxml-leftUpArrow") + || (rShapeType == "ooxml-uturnArrow" && nHandleIndex == 1)) + return (fW - fX) / std::min(fW, fH) * 50000.0; + + // pattern x / ss * 200000 + if (rShapeType == "ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 0) + return fX / std::min(fW, fH) * 200000.0; + + // pattern (hc - x) / w * 200000 + if ((rShapeType == "ooxml-downArrow" && nHandleIndex == 0) + || (rShapeType == "ooxml-ellipseRibbon") || (rShapeType == "ooxml-ellipseRibbon2") + || (rShapeType == "ooxml-leftRightArrowCallout" && nHandleIndex == 3) + || (rShapeType == "ooxml-ribbon") || (rShapeType == "ooxml-ribbon2") + || (rShapeType == "ooxml-upArrow" && nHandleIndex == 0) + || (rShapeType == "ooxml-upDownArrow" && nHandleIndex == 0)) + return (fW / 2.0 - fX) / fW * 200000.0; + + // pattern (x - hc) / w * 100000 + if ((rShapeType == "ooxml-cloudCallout") || (rShapeType == "ooxml-doubleWave") + || (rShapeType == "ooxml-wave") || (rShapeType == "ooxml-wedgeEllipseCallout") + || (rShapeType == "ooxml-wedgeRectCallout") + || (rShapeType == "ooxml-wedgeRoundRectCallout")) + return (fX - fW / 2.0) / fW * 100000.0; + + // pattern (x - hc) / w * 200000 + if (rShapeType == "ooxml-teardrop") + return (fX - fW / 2.0) / fW * 200000.0; + + // pattern (w - x) / w * 100000 or (r - x) / w * 100000 + if (rShapeType == "ooxml-leftArrowCallout" && nHandleIndex == 3) + return (fW - fX) / fW * 100000.0; + + // pattern (hc - x) / h * 100000 + if (rShapeType == "ooxml-mathDivide") + return (fW / 2.0 - fX) / fH * 100000.0; + + // pattern x / w * 100000, simple scaling + if (rShapeType.startsWith("ooxml-")) + return fX / fW * 100000.0; + + return fX; // method is unknown +} + +static double lcl_getYAdjustmentValue(const OUString& 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 == "ooxml-leftArrowCallout" && nHandleIndex == 1) + || (rShapeType == "ooxml-leftRightArrowCallout" && nHandleIndex == 1) + || (rShapeType == "ooxml-rightArrowCallout" && nHandleIndex == 1)) + return (fH / 2.0 - fY) / std::min(fW, fH) * 100000.0; + + // pattern (vc - y) / ss * 200000 + if ((rShapeType == "ooxml-curvedLeftArrow") || (rShapeType == "ooxml-curvedRightArrow") + || (rShapeType == "ooxml-leftArrowCallout" && nHandleIndex == 0) + || (rShapeType == "ooxml-leftRightArrowCallout" && nHandleIndex == 0) + || (rShapeType == "ooxml-mathPlus") + || (rShapeType == "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 == "ooxml-bentUpArrow" && nHandleIndex == 0) || (rShapeType == "ooxml-corner") + || (rShapeType == "ooxml-curvedDownArrow") || (rShapeType == "ooxml-downArrow") + || (rShapeType == "ooxml-downArrowCallout" && nHandleIndex == 2) + || (rShapeType == "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 == "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 == "ooxml-bentUpArrow" && nHandleIndex == 2) + || (rShapeType == "ooxml-bracePair") || (rShapeType == "ooxml-bracketPair") + || (rShapeType == "ooxml-can") || (rShapeType == "ooxml-cube") + || (rShapeType == "ooxml-curvedUpArrow") || (rShapeType == "ooxml-halfFrame") + || (rShapeType == "ooxml-leftBrace" && nHandleIndex == 0) + || (rShapeType == "ooxml-leftBracket") || (rShapeType == "ooxml-leftRightUpArrow") + || (rShapeType == "ooxml-leftUpArrow" && nHandleIndex == 2) + || (rShapeType == "ooxml-mathMultiply") || (rShapeType == "ooxml-quadArrow") + || (rShapeType == "ooxml-quadArrowCallout" && nHandleIndex == 2) + || (rShapeType == "ooxml-rightBrace" && nHandleIndex == 0) + || (rShapeType == "ooxml-rightBracket") || (rShapeType == "ooxml-upArrow") + || (rShapeType == "ooxml-upArrowCallout" && nHandleIndex == 2) + || (rShapeType == "ooxml-upDownArrow") + || (rShapeType == "ooxml-upDownArrowCallout" && nHandleIndex == 2) + || (rShapeType == "ooxml-verticalScroll")) + return fY / std::min(fW, fH) * 100000.0; + + // pattern y / ss * 50000 + if (rShapeType == "ooxml-bentArrow") + return fY / std::min(fW, fH) * 50000.0; + + // pattern (vc - y) / h * 100000 + if ((rShapeType == "ooxml-mathDivide" && nHandleIndex == 1) // -adj1 / 2 - adj3 outside + || (rShapeType == "ooxml-mathEqual" && nHandleIndex == 0) // -adj2 / 2 outside + || (rShapeType == "ooxml-mathNotEqual" && nHandleIndex == 0) // -adj3 / 2 outside + || (rShapeType == "ooxml-star4") || (rShapeType == "ooxml-star6") + || (rShapeType == "ooxml-star8") || (rShapeType == "ooxml-star10") + || (rShapeType == "ooxml-star12") || (rShapeType == "ooxml-star16") + || (rShapeType == "ooxml-star24") || (rShapeType == "ooxml-star32")) + return (fH / 2.0 - fY) / fH * 100000.0; + + // pattern (vc - y) / h * 200000 + if ((rShapeType == "ooxml-leftArrow") || (rShapeType == "ooxml-leftRightArrow") + || (rShapeType == "ooxml-mathDivide" && nHandleIndex == 0) + || (rShapeType == "ooxml-mathEqual" && nHandleIndex == 1) + || (rShapeType == "ooxml-mathMinus") || (rShapeType == "ooxml-notchedRightArrow") + || (rShapeType == "ooxml-mathNotEqual" && nHandleIndex == 2) + || (rShapeType == "ooxml-quadArrowCallout" && nHandleIndex == 3) + || (rShapeType == "ooxml-rightArrow") || (rShapeType == "ooxml-stripedRightArrow") + || (rShapeType == "ooxml-upDownArrowCallout" && nHandleIndex == 3)) + return (fH / 2.0 - fY) / fH * 200000.0; + + // pattern (y - vc) / h * 100000 + if ((rShapeType == "ooxml-cloudCallout") || (rShapeType == "ooxml-wedgeEllipseCallout") + || (rShapeType == "ooxml-wedgeRectCallout") + || (rShapeType == "ooxml-wedgeRoundRectCallout")) + return (fY - fH / 2.0) / fH * 100000.0; + + // pattern (h - y) / h * 100000 or (b - y) / h * 100000 + if ((rShapeType == "ooxml-ellipseRibbon" && nHandleIndex == 2) + || (rShapeType == "ooxml-ellipseRibbon2" && nHandleIndex == 0) + || (rShapeType == "ooxml-ribbon2") + || (rShapeType == "ooxml-upArrowCallout" && nHandleIndex == 3)) + return (fH - fY) / fH * 100000.0; + + // special pattern smiley + if (rShapeType == "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 == "ooxml-star5") + return (fH / 2.0 - fY * 100000.0 / 110557.0) / fH * 100000.0; + if (rShapeType == "ooxml-star7") + return (fH / 2.0 - fY * 100000.0 / 105210.0) / fH * 100000.0; + + // special pattern swooshArrow + if (rShapeType == "ooxml-swooshArrow") + return (fY - std::min(fW, fH) / 8.0) / fH * 100000.0; + + // special pattern leftRightRibbon + if (rShapeType == "ooxml-leftRightRibbon") + return fY / fH * 200000 - 100000; + + // pattern y / h * 100000, simple scaling + if (rShapeType.startsWith("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) - sqrt(fX * fX + fY * 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 = -nRotateAngle * F_PI18000; + RotatePoint( aP, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) ); + } + const GeoStat aGeoStat(mrSdrObjCustomShape.GetGeoStat()); + if ( aGeoStat.nShearAngle ) + { + double nTan = -aGeoStat.nTan; + 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 = sqrt(fOuterX * fOuterX + fOuterY * fOuterY); + double fHandleRadius = sqrt(fDX * fDX + fDY * 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 = sqrt(fDX * fDX + fDY * 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 = sqrt(fDX * fDX + fDY * 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(-F_PI2 - faA); // positive circle angle difference to 270 deg + if (abs(fha) == F_PI2) // 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, bool bFullCircle = false ) +{ + 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, bFullCircle ); + 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 += F_2PI; + } + 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< SdrPathObj*, 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(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 aPresetShapesWithU = + { "ellipse", "ring", "smiley", "sun", "forbidden", "flowchart-connector", + "flowchart-summing-junction", "flowchart-or", "cloud-callout"}; + std::unordered_set::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 : + { + 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(); + + [[fallthrough]]; + } + case ARCTO : + case CLOCKWISEARCTO : + { + bool bClockwise = ( nCommand == CLOCKWISEARC ) || ( nCommand == CLOCKWISEARCTO ); + sal_uInt32 nXor = bClockwise ? 3 : 2; + for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( ( rSrcPt + 3 ) < nCoordSize ); i++ ) + { + 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( rSrcPt + nXor ) ], true, true ) ); + Point aEnd( GetPoint( seqCoordinates[ static_cast( 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(rSrcPt)], false /*bScale*/, false /*bReplaceGeoSize*/); + fWR = aTempPair.getX(); + fHR = aTempPair.getY(); + aTempPair = GetPointAsB2DPoint(seqCoordinates[static_cast(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(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.getX() + { + if (aEnd.getY() 1) + { + // #i76201# Add conversion to closed polygon when first and last points are equal + basegfx::utils::checkClosed(aNewB2DPolygon); + aNewB2DPolyPolygon.append(aNewB2DPolygon); + } + + if(aNewB2DPolyPolygon.count()) + { + // #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); + SdrPathObj* pFill = new SdrPathObj( + mrSdrObjCustomShape.getSdrModelFromSdrObject(), + OBJ_POLY, + aClosedPolyPolygon); + SfxItemSet aTempSet(*this); + aTempSet.Put(makeSdrShadowItem(false)); + aTempSet.Put(XLineStyleItem(drawing::LineStyle_NONE)); + pFill->SetMergedItemSet(aTempSet); + rObjectList.push_back(std::pair< SdrPathObj*, double >(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 + SdrPathObj* pStroke = new SdrPathObj( + mrSdrObjCustomShape.getSdrModelFromSdrObject(), + aNewB2DPolyPolygon.isClosed() ? OBJ_POLY : OBJ_PLIN, + aNewB2DPolyPolygon); + SfxItemSet aTempSet(*this); + aTempSet.Put(makeSdrShadowItem(false)); + aTempSet.Put(XFillStyleItem(drawing::FillStyle_NONE)); + pStroke->SetMergedItemSet(aTempSet); + rObjectList.push_back(std::pair< SdrPathObj*, double >(pStroke, dBrightness)); + } + } + else + { + SdrPathObj* pObj = nullptr; + SfxItemSet aTempSet(*this); + aTempSet.Put(makeSdrShadowItem(false)); + + if(bNoFill) + { + // see comment above about OBJ_PLIN + pObj = new SdrPathObj( + mrSdrObjCustomShape.getSdrModelFromSdrObject(), + aNewB2DPolyPolygon.isClosed() ? OBJ_POLY : OBJ_PLIN, + aNewB2DPolyPolygon); + aTempSet.Put(XFillStyleItem(drawing::FillStyle_NONE)); + } + else + { + aNewB2DPolyPolygon.setClosed(true); + pObj = new SdrPathObj( + mrSdrObjCustomShape.getSdrModelFromSdrObject(), + OBJ_POLY, + aNewB2DPolyPolygon); + } + + if(bNoStroke) + { + aTempSet.Put(XLineStyleItem(drawing::LineStyle_NONE)); + } + + pObj->SetMergedItemSet(aTempSet); + rObjectList.push_back(std::pair< SdrPathObj*, double >(pObj, dBrightness)); + } + } +} + +static void CorrectCalloutArrows( + MSO_SPT eSpType, + sal_uInt32 nLineObjectCount, + std::vector< std::pair< SdrPathObj*, 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< SdrPathObj*, double >& rCandidate : vObjectList ) + { + SdrPathObj* pObj(rCandidate.first); + + 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< SdrPathObj*, double >& rCandidate : vObjectList ) + { + SdrPathObj* pObj(rCandidate.first); + + 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< SdrPathObj*, double >& rCandidate : vObjectList ) + { + SdrPathObj* pObj(rCandidate.first); + + 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() ) + { + const drawing::FillStyle eFillStyle = rObj.GetMergedItem(XATTR_FILLSTYLE).GetValue(); + switch( eFillStyle ) + { + default: + case drawing::FillStyle_SOLID: + { + Color aFillColor; + + if ( nColorCount || 0.0 != dBrightness ) + { + 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++; + } +} + +SdrObject* EnhancedCustomShape2d::CreatePathObj( bool bLineGeometryNeededOnly ) +{ + if ( !seqCoordinates.hasElements() ) + { + return nullptr; + } + + std::vector< std::pair< SdrPathObj*, double > > vObjectList; + const bool bSortFilledObjectsToBack(SortFilledObjectsToBackByDefault(eSpType)); + sal_Int32 nSubPathIndex(0); + sal_Int32 nSrcPt(0); + sal_Int32 nSegmentInd(0); + SdrObject* pRet(nullptr); + + 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< SdrPathObj*, double> > vNewList; + + for ( const std::pair< SdrPathObj*, double >& rCandidate : vObjectList ) + { + SdrPathObj* pObj(rCandidate.first); + const drawing::LineStyle eLineStyle(pObj->GetMergedItem(XATTR_LINESTYLE).GetValue()); + const drawing::FillStyle eFillStyle(pObj->GetMergedItem(XATTR_FILLSTYLE).GetValue()); + + // #i40600# if bLineGeometryNeededOnly is set, linestyle does not matter + if(!bLineGeometryNeededOnly && (drawing::LineStyle_NONE == eLineStyle) && (drawing::FillStyle_NONE == eFillStyle)) + { + // always use SdrObject::Free(...) for SdrObjects (!) + SdrObject* pTemp(pObj); + SdrObject::Free(pTemp); + } + else + { + vNewList.push_back(rCandidate); + } + } + + vObjectList = 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< SdrPathObj*, double >& rCandidate : vObjectList ) + { + SdrPathObj* pObj(rCandidate.first); + + 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< SdrPathObj*, double> > vTempList; + vTempList.reserve(vObjectList.size()); + + for ( const std::pair< SdrPathObj*, double >& rCandidate : vObjectList ) + { + SdrPathObj* pObj(rCandidate.first); + + if ( !pObj->IsLine() ) + { + vTempList.push_back(rCandidate); + } + } + + for ( const std::pair< SdrPathObj*, double >& rCandidate : vObjectList ) + { + SdrPathObj* pObj(rCandidate.first); + + if ( pObj->IsLine() ) + { + vTempList.push_back(rCandidate); + } + } + + vObjectList = vTempList; + } + } + } + + // #i37011# + if(!vObjectList.empty()) + { + // copy remaining objects to pRet + if(vObjectList.size() > 1) + { + pRet = new SdrObjGroup(mrSdrObjCustomShape.getSdrModelFromSdrObject()); + + for ( const std::pair< SdrPathObj*, double >& rCandidate : vObjectList ) + { + SdrPathObj* pObj(rCandidate.first); + + pRet->GetSubList()->NbcInsertObject(pObj); + } + } + else if(1 == vObjectList.size()) + { + pRet = vObjectList.begin()->first; + } + + if(pRet) + { + // move to target position + tools::Rectangle aCurRect(pRet->GetSnapRect()); + aCurRect.Move(aLogicRect.Left(), aLogicRect.Top()); + pRet->NbcSetSnapRect(aCurRect); + } + } + + return pRet; +} + +SdrObject* EnhancedCustomShape2d::CreateObject( bool bLineGeometryNeededOnly ) +{ + SdrObject* pRet = nullptr; + + if ( eSpType == mso_sptRectangle ) + { + pRet = new SdrRectObj(mrSdrObjCustomShape.getSdrModelFromSdrObject(), aLogicRect); + pRet->SetMergedItemSet( *this ); + } + if ( !pRet ) + pRet = CreatePathObj( bLineGeometryNeededOnly ); + + return pRet; +} + +void EnhancedCustomShape2d::ApplyGluePoints( SdrObject* pObj ) +{ + if ( pObj ) + { + 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 ); + } + } +} + +SdrObject* 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..c802d0057 --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShape3d.cxx @@ -0,0 +1,815 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + 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; +} + +} + +EnhancedCustomShape3d::Transformation2D::Transformation2D( + const SdrObjCustomShape& rSdrObjCustomShape, + const double *pMap) +: aCenter(rSdrObjCustomShape.GetSnapRect().Center()) + , eProjectionMode( drawing::ProjectionMode_PARALLEL ) + , fSkewAngle(0.0) + , fSkew(0.0) + , fOriginX(0.0) + , fOriginY(0.0) +{ + const SdrCustomShapeGeometryItem& rGeometryItem(rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )); + const Any* pAny = rGeometryItem.GetPropertyValueByName( "Extrusion", "ProjectionMode" ); + if ( pAny ) + *pAny >>= eProjectionMode; + + if ( eProjectionMode == drawing::ProjectionMode_PARALLEL ) + GetSkew( rGeometryItem, fSkew, fSkewAngle ); + else + { + GetOrigin( rGeometryItem, fOriginX, fOriginY ); + fOriginX = fOriginX * rSdrObjCustomShape.GetLogicRect().GetWidth(); + fOriginY = fOriginY * rSdrObjCustomShape.GetLogicRect().GetHeight(); + + drawing::Position3D aViewPointDefault( 3472, -3472, 25000 ); + drawing::Position3D aViewPoint( GetPosition3D( rGeometryItem, "ViewPoint", aViewPointDefault, pMap ) ); + fViewPoint.setX(aViewPoint.PositionX); + fViewPoint.setY(aViewPoint.PositionY); + fViewPoint.setZ(-aViewPoint.PositionZ); + } +} + +basegfx::B3DPolygon EnhancedCustomShape3d::Transformation2D::ApplySkewSettings( const basegfx::B3DPolygon& rPoly3D ) const +{ + basegfx::B3DPolygon aRetval; + + sal_uInt32 j; + for ( j = 0; j < rPoly3D.count(); j++ ) + { + const basegfx::B3DPoint aPoint(rPoly3D.getB3DPoint(j)); + double fDepth(-( aPoint.getZ() * fSkew ) / 100.0); + aRetval.append(basegfx::B3DPoint( + aPoint.getX() + (fDepth * cos( fSkewAngle )), + aPoint.getY() - (fDepth * sin( fSkewAngle )), + aPoint.getZ())); + } + + return aRetval; +} + +Point EnhancedCustomShape3d::Transformation2D::Transform2D( const basegfx::B3DPoint& rPoint3D ) const +{ + Point aPoint2D; + if ( eProjectionMode == drawing::ProjectionMode_PARALLEL ) + { + aPoint2D.setX( static_cast(rPoint3D.getX()) ); + aPoint2D.setY( static_cast(rPoint3D.getY()) ); + } + else + { + double fX = rPoint3D.getX() - fOriginX; + double fY = rPoint3D.getY() - fOriginY; + double f = ( - fViewPoint.getZ() ) / ( rPoint3D.getZ() - fViewPoint.getZ() ); + aPoint2D.setX( static_cast(( fX - fViewPoint.getX() ) * f + fViewPoint.getX() + fOriginX ) ); + aPoint2D.setY( static_cast(( fY - fViewPoint.getY() ) * f + fViewPoint.getY() + fOriginY ) ); + } + aPoint2D.Move( aCenter.X(), aCenter.Y() ); + return aPoint2D; +} + +bool EnhancedCustomShape3d::Transformation2D::IsParallel() const +{ + return eProjectionMode == css::drawing::ProjectionMode_PARALLEL; +} + +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" ); + fMap *= 1440.0 / 2540.0; + pMap = &fMap; + } + + if ( GetBool( rGeometryItem, "Extrusion", false ) ) + { + bool bIsMirroredX(rSdrObjCustomShape.IsMirroredX()); + bool bIsMirroredY(rSdrObjCustomShape.IsMirroredY()); + tools::Rectangle aSnapRect(rSdrObjCustomShape.GetLogicRect()); + long nObjectRotation(rSdrObjCustomShape.GetRotateAngle()); + if ( nObjectRotation ) + { + double a = (36000 - nObjectRotation) * F_PI18000; + long dx = aSnapRect.Right() - aSnapRect.Left(); + 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; + ProjectionType eProjectionType( eProjectionMode == drawing::ProjectionMode_PARALLEL ? ProjectionType::Parallel : ProjectionType::Perspective ); + // 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( 0 ) ); + aSet.Put( makeSvx3DPercentDiagonalItem( 0 ) ); + aSet.Put( Svx3DTextureModeItem( 1 ) ); + aSet.Put( Svx3DNormalsKindItem( 1 ) ); + + 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; + 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(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( 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())); + 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(aBoundRect.GetWidth()) / static_cast(aSnapRect.GetWidth()); + double fYScale = static_cast(aBoundRect.GetHeight()) / static_cast(aSnapRect.GetHeight()); + + Point aPt( static_cast( static_cast( aBoundRect.Left() - aSnapRect.Left() )* static_cast(aBmpSize.Width()) / static_cast(aSnapRect.GetWidth()) ), + static_cast( static_cast( aBoundRect.Top() - aSnapRect.Top() ) * static_cast(aBmpSize.Height()) / static_cast(aSnapRect.GetHeight()) ) ); + Size aSize( static_cast( aBmpSize.Width() * fXScale ), + static_cast( 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(); + const basegfx::B3DRange& rVolume = pScene->GetBoundVolume(); + pScene->NbcSetSnapRect( aSnapRect ); + + // InitScene replacement + double fW = rVolume.getWidth(); + double fH = rVolume.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 ); + rCamera.SetProjection( eProjectionType ); + pScene->SetCamera( rCamera ); + pScene->SetRectsDirty(); + + double fOriginX, fOriginY; + GetOrigin( rGeometryItem, fOriginX, fOriginY ); + fOriginX = fOriginX * aSnapRect.GetWidth(); + fOriginY = fOriginY * aSnapRect.GetHeight(); + + basegfx::B3DHomMatrix aNewTransform( pScene->GetTransform() ); + aNewTransform.translate( -aCenter.X(), aCenter.Y(), -pScene->GetBoundVolume().getDepth() ); + + double fXRotate, fYRotate; + GetRotateAngle( rGeometryItem, fXRotate, fYRotate ); + double fZRotate(basegfx::deg2rad(rSdrObjCustomShape.GetObjectRotation())); + if ( fZRotate != 0.0 ) + aNewTransform.rotate( 0.0, 0.0, fZRotate ); + if ( bIsMirroredX ) + aNewTransform.scale( -1.0, 1, 1 ); + if ( bIsMirroredY ) + aNewTransform.scale( 1, -1.0, 1 ); + if( fYRotate != 0.0 ) + aNewTransform.rotate( 0.0, -fYRotate, 0.0 ); + if( fXRotate != 0.0 ) + aNewTransform.rotate( -fXRotate, 0.0, 0.0 ); + if ( eProjectionType == ProjectionType::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)); + } + } + 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 + { + aNewTransform.translate( -fOriginX, fOriginY, 0.0 ); + // now set correct camera position + drawing::Position3D aViewPointDefault( 3472, -3472, 25000 ); + drawing::Position3D aViewPoint( GetPosition3D( rGeometryItem, "ViewPoint", aViewPointDefault, pMap ) ); + double fViewPointX = aViewPoint.PositionX; + double fViewPointY = aViewPoint.PositionY; + double fViewPointZ = aViewPoint.PositionZ; + basegfx::B3DPoint _aLookAt( fViewPointX, -fViewPointY, 0.0 ); + basegfx::B3DPoint aNewCamPos( fViewPointX, -fViewPointY, fViewPointZ ); + rCamera.SetPosAndLookAt( aNewCamPos, _aLookAt ); + pScene->SetCamera( rCamera ); + } + + pScene->NbcSetTransform( aNewTransform ); + + + // light + + double fAmbientIntensity = GetDouble( rGeometryItem, "Brightness", 22178.0 / 655.36 ) / 100.0; + + drawing::Direction3D aFirstLightDirectionDefault( 50000, 0, 10000 ); + drawing::Direction3D aFirstLightDirection( GetDirection3D( rGeometryItem, "FirstLightDirection", aFirstLightDirectionDefault ) ); + if ( aFirstLightDirection.DirectionZ == 0.0 ) + aFirstLightDirection.DirectionZ = 1.0; + + double fLightIntensity = GetDouble( rGeometryItem, "FirstLightLevel", 43712.0 / 655.36 ) / 100.0; + + /* sal_Bool bFirstLightHarsh = */ GetBool( rGeometryItem, "FirstLightHarsh", false ); + + drawing::Direction3D aSecondLightDirectionDefault( -50000, 0, 10000 ); + drawing::Direction3D aSecondLightDirection( GetDirection3D( rGeometryItem, "SecondLightDirection", aSecondLightDirectionDefault ) ); + if ( aSecondLightDirection.DirectionZ == 0.0 ) + aSecondLightDirection.DirectionZ = -1; + + double fLight2Intensity = GetDouble( rGeometryItem, "SecondLightLevel", 43712.0 / 655.36 ) / 100.0; + + /* sal_Bool bLight2Harsh = */ GetBool( rGeometryItem, "SecondLightHarsh", false ); + /* sal_Bool bLightFace = */ GetBool( rGeometryItem, "LightFace", false ); + + sal_uInt16 nAmbientColor = static_cast( fAmbientIntensity * 255.0 ); + if ( nAmbientColor > 255 ) + nAmbientColor = 255; + Color aGlobalAmbientColor( static_cast(nAmbientColor), static_cast(nAmbientColor), static_cast(nAmbientColor) ); + pScene->GetProperties().SetObjectItem( makeSvx3DAmbientcolorItem( aGlobalAmbientColor ) ); + + sal_uInt8 nSpotLight1 = static_cast( fLightIntensity * 255.0 ); + basegfx::B3DVector aSpotLight1( aFirstLightDirection.DirectionX, - ( aFirstLightDirection.DirectionY ), -( aFirstLightDirection.DirectionZ ) ); + aSpotLight1.normalize(); + pScene->GetProperties().SetObjectItem( makeSvx3DLightOnOff1Item( true ) ); + Color aAmbientSpot1Color( nSpotLight1, nSpotLight1, nSpotLight1 ); + pScene->GetProperties().SetObjectItem( makeSvx3DLightcolor1Item( aAmbientSpot1Color ) ); + pScene->GetProperties().SetObjectItem( makeSvx3DLightDirection1Item( aSpotLight1 ) ); + + sal_uInt8 nSpotLight2 = static_cast( fLight2Intensity * 255.0 ); + basegfx::B3DVector aSpotLight2( aSecondLightDirection.DirectionX, -aSecondLightDirection.DirectionY, -aSecondLightDirection.DirectionZ ); + aSpotLight2.normalize(); + pScene->GetProperties().SetObjectItem( makeSvx3DLightOnOff2Item( true ) ); + Color aAmbientSpot2Color( nSpotLight2, nSpotLight2, nSpotLight2 ); + pScene->GetProperties().SetObjectItem( makeSvx3DLightcolor2Item( aAmbientSpot2Color ) ); + pScene->GetProperties().SetObjectItem( makeSvx3DLightDirection2Item( aSpotLight2 ) ); + + sal_uInt8 nSpotLight3 = 70; + basegfx::B3DVector aSpotLight3( 0.0, 0.0, 1.0 ); + pScene->GetProperties().SetObjectItem( makeSvx3DLightOnOff3Item( true ) ); + Color aAmbientSpot3Color( nSpotLight3, nSpotLight3, nSpotLight3 ); + pScene->GetProperties().SetObjectItem( makeSvx3DLightcolor3Item( aAmbientSpot3Color ) ); + pScene->GetProperties().SetObjectItem( makeSvx3DLightDirection3Item( aSpotLight3 ) ); + + double fSpecular = GetDouble( rGeometryItem, "Specularity", 0 ) / 100; + bool bMetal = GetBool( rGeometryItem, "Metal", false ); + + Color aSpecularCol( 225,225,225 ); + if ( bMetal ) + { + aSpecularCol = Color( 200, 200, 200 ); + fSpecular += 0.15; + } + sal_Int32 nIntensity = static_cast(fSpecular) * 100; + if ( nIntensity > 100 ) + nIntensity = 100; + else if ( nIntensity < 0 ) + nIntensity = 0; + nIntensity = 100 - nIntensity; + pScene->GetProperties().SetObjectItem( makeSvx3DMaterialSpecularItem( aSpecularCol ) ); + pScene->GetProperties().SetObjectItem( makeSvx3DMaterialSpecularIntensityItem( static_cast(nIntensity) ) ); + + pScene->SetLogicRect( + CalculateNewSnapRect( + rSdrObjCustomShape, + aSnapRect, + aBoundRect2d, + pMap)); + + // 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; +} + +tools::Rectangle EnhancedCustomShape3d::CalculateNewSnapRect( + const SdrObjCustomShape& rSdrObjCustomShape, + const tools::Rectangle& rSnapRect, + const tools::Rectangle& rBoundRect, + const double* pMap) +{ + const SdrCustomShapeGeometryItem& rGeometryItem(rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )); + const Point aCenter( rSnapRect.Center() ); + double fExtrusionBackward, fExtrusionForward; + GetExtrusionDepth( rGeometryItem, pMap, fExtrusionBackward, fExtrusionForward ); + sal_uInt32 i; + + // creating initial bound volume ( without rotation. skewing.and camera ) + basegfx::B3DPolygon aBoundVolume; + const tools::Polygon aPolygon( rBoundRect ); + + for ( i = 0; i < 4; i++ ) + { + aBoundVolume.append(basegfx::B3DPoint(aPolygon[ static_cast(i) ].X() - aCenter.X(), aPolygon[ static_cast(i) ].Y() - aCenter.Y(), fExtrusionForward)); + } + + for ( i = 0; i < 4; i++ ) + { + aBoundVolume.append(basegfx::B3DPoint(aPolygon[ static_cast(i) ].X() - aCenter.X(), aPolygon[ static_cast(i) ].Y() - aCenter.Y(), fExtrusionBackward)); + } + + drawing::Direction3D aRotationCenterDefault( 0, 0, 0 ); // default seems to be wrong, a fractional size of shape has to be used!! + drawing::Direction3D aRotationCenter( GetDirection3D( rGeometryItem, "RotationCenter", aRotationCenterDefault ) ); + + double fXRotate, fYRotate; + GetRotateAngle( rGeometryItem, fXRotate, fYRotate ); + double fZRotate(basegfx::deg2rad(rSdrObjCustomShape.GetObjectRotation())); + + // rotating bound volume + basegfx::B3DHomMatrix aMatrix; + aMatrix.translate(-aRotationCenter.DirectionX, -aRotationCenter.DirectionY, -aRotationCenter.DirectionZ); + if ( fZRotate != 0.0 ) + aMatrix.rotate( 0.0, 0.0, fZRotate ); + if (rSdrObjCustomShape.IsMirroredX()) + aMatrix.scale( -1.0, 1, 1 ); + if (rSdrObjCustomShape.IsMirroredY()) + aMatrix.scale( 1, -1.0, 1 ); + if( fYRotate != 0.0 ) + aMatrix.rotate( 0.0, fYRotate, 0.0 ); + if( fXRotate != 0.0 ) + aMatrix.rotate( -fXRotate, 0.0, 0.0 ); + aMatrix.translate(aRotationCenter.DirectionX, aRotationCenter.DirectionY, aRotationCenter.DirectionZ); + aBoundVolume.transform(aMatrix); + + Transformation2D aTransformation2D( + rSdrObjCustomShape, + pMap); + + if ( aTransformation2D.IsParallel() ) + aBoundVolume = aTransformation2D.ApplySkewSettings( aBoundVolume ); + + tools::Polygon aTransformed( 8 ); + for ( i = 0; i < 8; i++ ) + aTransformed[ static_cast(i) ] = aTransformation2D.Transform2D( aBoundVolume.getB3DPoint( i ) ); + + return aTransformed.GetBoundRect(); +} + +/* 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..233b99441 --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShape3d.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_SOURCE_CUSTOMSHAPES_ENHANCEDCUSTOMSHAPE3D_HXX +#define INCLUDED_SVX_SOURCE_CUSTOMSHAPES_ENHANCEDCUSTOMSHAPE3D_HXX + +#include +#include +#include + +#include + +class SdrObject; +class SdrObjCustomShape; + +class EnhancedCustomShape3d final +{ + class Transformation2D + { + Point aCenter; + css::drawing::ProjectionMode eProjectionMode; + + // parallel projection + double fSkewAngle; + double fSkew; // in percent + + // perspective projection + basegfx::B3DPoint fViewPoint; + double fOriginX; + double fOriginY; + + public: + Transformation2D( + const SdrObjCustomShape& rSdrObjCustomShape, + const double* pMap); + + basegfx::B3DPolygon ApplySkewSettings( const basegfx::B3DPolygon& rPolygon3D ) const; + Point Transform2D( const basegfx::B3DPoint& rPoint ) const; + bool IsParallel() const; + }; + + friend class Transformation2D; + + static tools::Rectangle CalculateNewSnapRect( + const SdrObjCustomShape& rSdrObjCustomShape, + const tools::Rectangle& rSnapRect, + const tools::Rectangle& rBoundRect, + const double* pMap); + +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..1f61c6097 --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShapeEngine.cxx @@ -0,0 +1,511 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "EnhancedCustomShape3d.hxx" +#include "EnhancedCustomShapeFontWork.hxx" +#include "EnhancedCustomShapeHandle.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 ImplForceGroupWithText( + const SdrObjCustomShape& rSdrObjCustomShape, + std::unique_ptr pRenderedShape); + +public: + EnhancedCustomShapeEngine(); + + // XInterface + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() 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() throw() +{ + OWeakObject::acquire(); +} +void SAL_CALL EnhancedCustomShapeEngine::release() throw() +{ + 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 EnhancedCustomShapeEngine::ImplForceGroupWithText( + const SdrObjCustomShape& rSdrObjCustomShape, + std::unique_ptr pRenderedShape) +{ + const bool bHasText(rSdrObjCustomShape.HasText()); + + if ( pRenderedShape || bHasText ) + { + // applying shadow + const SdrObject* pShadowGeometry(rSdrObjCustomShape.GetSdrObjectShadowFromCustomShape()); + + if ( pShadowGeometry ) + { + if ( pRenderedShape ) + { + if ( dynamic_cast( pRenderedShape.get() ) == nullptr ) + { + auto pTmp = std::move(pRenderedShape); + pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject())); + static_cast(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() ); + } + + static_cast(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 pTextObj( SdrObjFactory::MakeNewObject( + rSdrObjCustomShape.getSdrModelFromSdrObject(), + rSdrObjCustomShape.GetObjInventor(), + OBJ_TEXT) ); + + // Copy text content + OutlinerParaObject* pParaObj(rSdrObjCustomShape.GetOutlinerParaObject()); + + if( pParaObj ) + pTextObj->NbcSetOutlinerParaObject( std::make_unique(*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()); + const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape* >(GetSdrObjectFromXShape(mxShape))); + + if(bIsSdrObjCustomShape) + { + SdrObjCustomShape& rSdrObjCustomShape2( + static_cast< SdrObjCustomShape& >( + *GetSdrObjectFromXShape(mxShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape2); + 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.nSin, + rSourceGeo.nCos); + } + + // set modified ItemSet at text object + pTextObj->SetMergedItemSet(aTargetItemSet); + + if ( pRenderedShape ) + { + if ( dynamic_cast( pRenderedShape.get() ) == nullptr ) + { + auto pTmp = std::move(pRenderedShape); + pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject())); + static_cast(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() ); + } + static_cast(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTextObj.release() ); + } + else + pRenderedShape = std::move(pTextObj); + } + + // force group + if ( pRenderedShape ) + { + if ( dynamic_cast( pRenderedShape.get() ) == nullptr ) + { + auto pTmp = std::move(pRenderedShape); + pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject())); + static_cast(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() ); + } + } + } + + return pRenderedShape; +} + +void SetTemporary( uno::Reference< drawing::XShape > const & xShape ) +{ + if ( xShape.is() ) + { + SvxShape* pShape = comphelper::getUnoTunnelImplementation( xShape ); + if ( pShape ) + pShape->TakeSdrObjectOwnership(); + } +} + +Reference< drawing::XShape > SAL_CALL EnhancedCustomShapeEngine::render() +{ + const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape* >(GetSdrObjectFromXShape(mxShape))); + + if(!bIsSdrObjCustomShape) + { + return Reference< drawing::XShape >(); + } + + SdrObjCustomShape& rSdrObjCustomShape( + static_cast< SdrObjCustomShape& >( + *GetSdrObjectFromXShape(mxShape))); + + // retrieving the TextPath property to check if feature is enabled + const SdrCustomShapeGeometryItem& rGeometryItem(rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )); + bool bTextPathOn = false; + const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "TextPath", "TextPath" ); + if ( pAny ) + *pAny >>= bTextPathOn; + + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + sal_Int32 nRotateAngle = aCustomShape2d.GetRotateAngle(); + + bool bFlipV = aCustomShape2d.IsFlipVert(); + bool bFlipH = aCustomShape2d.IsFlipHorz(); + bool bLineGeometryNeededOnly = bTextPathOn; + + std::unique_ptr xRenderedShape(aCustomShape2d.CreateObject(bLineGeometryNeededOnly)); + if (xRenderedShape) + { + if ( bTextPathOn ) + { + std::unique_ptr xRenderedFontWork( + EnhancedCustomShapeFontWork::CreateFontWork( + xRenderedShape.get(), + rSdrObjCustomShape)); + + if (xRenderedFontWork) + { + xRenderedShape = std::move(xRenderedFontWork); + } + } + std::unique_ptr xRenderedShape3d(EnhancedCustomShape3d::Create3DObject(xRenderedShape.get(), rSdrObjCustomShape)); + if (xRenderedShape3d) + { + bFlipV = bFlipH = false; + nRotateAngle = 0; + xRenderedShape = std::move(xRenderedShape3d); + } + + tools::Rectangle aRect(rSdrObjCustomShape.GetSnapRect()); + const GeoStat& rGeoStat(rSdrObjCustomShape.GetGeoStat()); + + if ( rGeoStat.nShearAngle ) + { + long nShearAngle = rGeoStat.nShearAngle; + double nTan = rGeoStat.nTan; + if (bFlipV != bFlipH) + { + nShearAngle = -nShearAngle; + nTan = -nTan; + } + + xRenderedShape->Shear(rSdrObjCustomShape.GetSnapRect().Center(), nShearAngle, nTan, false); + } + if(nRotateAngle ) + { + double a = nRotateAngle * F_PI18000; + + xRenderedShape->NbcRotate(rSdrObjCustomShape.GetSnapRect().Center(), nRotateAngle, sin( a ), cos( a )); + } + 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(rSdrObjCustomShape.GetStyleSheet(), true); + xRenderedShape->RecalcSnapRect(); + } + + if ( mbForceGroupWithText ) + { + xRenderedShape = ImplForceGroupWithText( + rSdrObjCustomShape, + 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; + const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape* >(GetSdrObjectFromXShape(mxShape))); + + if(bIsSdrObjCustomShape) + { + SdrObjCustomShape& rSdrObjCustomShape(static_cast< SdrObjCustomShape& >(*GetSdrObjectFromXShape(mxShape))); + uno::Reference< document::XActionLockable > xLockable( mxShape, uno::UNO_QUERY ); + + if(xLockable.is() && !xLockable->isActionLocked()) + { + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + 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; + const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape* >(GetSdrObjectFromXShape(mxShape))); + + if(bIsSdrObjCustomShape) + { + SdrObjCustomShape& rSdrObjCustomShape( + static_cast< SdrObjCustomShape& >( + *GetSdrObjectFromXShape(mxShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + SdrObject* pObj = aCustomShape2d.CreateLineGeometry(); + + if ( pObj ) + { + tools::Rectangle aRect(rSdrObjCustomShape.GetSnapRect()); + bool bFlipV = aCustomShape2d.IsFlipVert(); + bool bFlipH = aCustomShape2d.IsFlipHorz(); + const GeoStat& rGeoStat(rSdrObjCustomShape.GetGeoStat()); + + if ( rGeoStat.nShearAngle ) + { + long nShearAngle = rGeoStat.nShearAngle; + double nTan = rGeoStat.nTan; + if (bFlipV != bFlipH) + { + nShearAngle = -nShearAngle; + nTan = -nTan; + } + pObj->Shear( aRect.Center(), nShearAngle, nTan, false); + } + sal_Int32 nRotateAngle = aCustomShape2d.GetRotateAngle(); + if( nRotateAngle ) + { + double a = nRotateAngle * F_PI18000; + pObj->NbcRotate( aRect.Center(), nRotateAngle, sin( a ), cos( a ) ); + } + 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(pNext) ) + { + aPP = pPathObj->GetPathPoly(); + } + else + { + SdrObjectUniquePtr pNewObj = pNext->ConvertToPolyObj( false, false ); + SdrPathObj* pPath = dynamic_cast( pNewObj.get() ); + if ( pPath ) + aPP = pPath->GetPathPoly(); + } + + if ( aPP.count() ) + aPolyPolygon.append(aPP); + } + SdrObject::Free( pObj ); + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( aPolyPolygon, + aPolyPolygonBezierCoords ); + } + } + + return aPolyPolygonBezierCoords; +} + +Sequence< Reference< drawing::XCustomShapeHandle > > SAL_CALL EnhancedCustomShapeEngine::getInteraction() +{ + sal_uInt32 i, nHdlCount = 0; + const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape* >(GetSdrObjectFromXShape(mxShape))); + + if(bIsSdrObjCustomShape) + { + SdrObjCustomShape& rSdrObjCustomShape( + static_cast< SdrObjCustomShape& >( + *GetSdrObjectFromXShape(mxShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + nHdlCount = aCustomShape2d.GetHdlCount(); + } + + Sequence< Reference< drawing::XCustomShapeHandle > > aSeq( nHdlCount ); + + for ( i = 0; i < nHdlCount; i++ ) + aSeq[ 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 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..cddb4571e --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx @@ -0,0 +1,903 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + bool bScalingFactorDefined = false; + 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(); + + 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 ); + // initializing virtual device + + ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::BITMASK); + pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM)); + pVirDev->SetFont( aFont ); + + if ( nOutlinesCount2d & 1 ) + bSingleLineMode = true; + + do + { + i = 0; + 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 || ( rFWData.bScaleX && fScalingFactor < 1.0 ) ) + { + fScalingFactor = fScale; + } + } + } + } + + if (fScalingFactor < 1.0) + { + nFontSize--; + aFont.SetFontHeight( nFontSize ); + pVirDev->SetFont( aFont ); + } + } + while (rFWData.bScaleX && fScalingFactor < 1.0 && nFontSize > 1 ); + + if (nFontSize > 1) + rFWData.fVerticalTextScaling = static_cast(nFontSize) / rFontHeight.GetHeight(); + // Add some padding + if (rFWData.bScaleX) + fScalingFactor *= 1.1; + + 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(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 ); + + 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::BITMASK); + pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM)); + pVirDev->SetFont( aFont ); + pVirDev->EnableRTL(); + if ( rParagraph.nFrameDirection == SvxFrameDirection::Horizontal_RL_TB ) + pVirDev->SetLayoutMode( ComplexTextLayoutFlags::BiDiRtl ); + + const SvxCharScaleWidthItem& rCharScaleWidthItem = rSdrObjCustomShape.GetMergedItem( EE_CHAR_FONTWIDTH ); + sal_uInt16 nCharScaleWidth = rCharScaleWidthItem.GetValue(); + std::unique_ptr pDXArry; + 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, pDXArry.get() ) ) + { + 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 ); + 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 + { + if ( ( nCharScaleWidth != 100 ) && nCharScaleWidth ) + { // applying character spacing + pDXArry.reset(new long[ rText.getLength() ]); + pVirDev->GetTextArray( rText, pDXArry.get()); + FontMetric aFontMetric( pVirDev->GetFontMetric() ); + aFont.SetAverageFontWidth( static_cast( static_cast(aFontMetric.GetAverageFontWidth()) * ( double(100) / static_cast(nCharScaleWidth) ) ) ); + pVirDev->SetFont( aFont ); + } + FWCharacterData aCharacterData; + if ( pVirDev->GetTextOutlines( aCharacterData.vOutlines, rText, 0, 0, -1, nWidth, pDXArry.get() ) ) + { + 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(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( ( static_cast( 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(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( 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) + { + 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 ( dynamic_cast( pPartObj) != nullptr ) + { + basegfx::B2DPolyPolygon aCandidate(static_cast(pPartObj)->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 ) + { + 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; + + 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( rPoint.X() - rTextAreaBoundRect.Left() ) / static_cast(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( rPt0.X() + fX * fd ), static_cast( 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( rPt0.X() + fX * fd ), static_cast( 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 ) + { + std::vector< double >::const_iterator aIter = std::lower_bound( rDistances.begin(), rDistances.end(), fX ); + sal_uInt16 nIdx = sal::static_int_cast( 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 ) ) + { + nIdx = sal::static_int_cast( 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(nWidth); + double fM2 = fx2 / static_cast(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( ( fx1 + fvx )- aBoundRect.Center().X() ), static_cast( ( 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(rPoint.X()) / static_cast(nWidth); + double fY = static_cast(rPoint.Y()) / static_cast(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( fx1 + fWidth * fY ) ); + rPoint.setY( static_cast( 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(), + OBJ_POLY, + 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 + +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..2ef6b040e --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx @@ -0,0 +1,1160 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include + +#include + +// 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 + +#include +#include +#include + +#include +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(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(aFract.GetNumerator()); + aEquation.nPara[ 2 ] = static_cast(aFract.GetDenominator()); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= static_cast(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 mpArg; + +public: + UnaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr& rArg ) : + meFunct( eFunct ), + mpArg( rArg ) + { + } + static double getValue( const ExpressionFunct eFunct, const std::shared_ptr& 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()( (*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(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(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(rEquations.size()); + rEquations.push_back( _aEquation ); + } + FillEquationParameter( aSource, 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= static_cast(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(rEquations.size()); + rEquations.push_back( aTmpEquation ); + } + FillEquationParameter( aSource, 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= static_cast(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(rEquations.size()); + rEquations.push_back( aTmpEquation ); + } + FillEquationParameter( aSource, 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= static_cast(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(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 mpFirstArg; + std::shared_ptr mpSecondArg; + +public: + + BinaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr& rFirstArg, const std::shared_ptr& 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& rFirstArg, const std::shared_ptr& 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(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(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(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(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(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(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(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(mpFirstArg.get())->mpFirstArg->getType() == ExpressionFunct::EnumPi ) + && ( static_cast(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(mpSecondArg.get())->mpFirstArg->getType() == ExpressionFunct::EnumPi ) + && ( static_cast(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(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(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(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(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(rEquations.size()); + rEquations.push_back( aEquation ); + } + break; + default: + break; + } + return aRet; + } +}; + +class IfExpression : public ExpressionNode +{ + std::shared_ptr mpFirstArg; + std::shared_ptr mpSecondArg; + std::shared_ptr mpThirdArg; + +public: + + IfExpression( const std::shared_ptr& rFirstArg, + const std::shared_ptr& rSecondArg, + const std::shared_ptr& 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(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 > 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( 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( *mxContext->mpCustoShape, aVal.toInt32() ) ); + } + break; + case ExpressionFunct::EnumEquation : + { + OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); + mxContext->maOperandStack.push( std::make_shared( *mxContext->mpCustoShape, aVal.toInt32() ) ); + } + break; + default: + mxContext->maOperandStack.push( std::make_shared( *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 pArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + + if( pArg->isConstant() ) // check for constness + rNodeStack.push( std::make_shared( UnaryFunctionExpression::getValue( meFunct, pArg ) ) ); + else // push complex node, that calcs the value on demand + rNodeStack.push( std::make_shared( 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 pSecondArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + std::shared_ptr pFirstArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + + // create combined ExpressionNode + auto pNode = std::make_shared( 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( (*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 pThirdArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + std::shared_ptr pSecondArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + std::shared_ptr pFirstArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + + // create combined ExpressionNode + auto pNode = std::make_shared( pFirstArg, pSecondArg, pThirdArg ); + // check for constness + if( pFirstArg->isConstant() && pSecondArg->isConstant() && pThirdArg->isConstant() ) + rNodeStack.push( std::make_shared( (*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 +{ + 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 >()[ 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(); + + // 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 const & FunctionParser::parseFunction( const OUString& 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 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..c0d81e213 --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShapeGeometry.cxx @@ -0,0 +1,8563 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include +#include + +static const sal_Int32 MIN_INT32 = std::numeric_limits::min(); + +static const sal_Int32 mso_sptDefault1400[] = +{ + 1, 1400 +}; +static const sal_Int32 mso_sptDefault1800[] = +{ + 1, 1800 +}; +static const sal_Int32 mso_sptDefault2500[] = +{ + 1, 2500 +}; +static const sal_Int32 mso_sptDefault2700[] = +{ + 1, 2700 +}; +static const sal_Int32 mso_sptDefault3600[] = +{ + 1, 3600 +}; +static const sal_Int32 mso_sptDefault3700[] = +{ + 1, 3700 +}; +static const sal_Int32 mso_sptDefault5400[] = +{ + 1, 5400 +}; +static const sal_Int32 mso_sptDefault7200[] = +{ + 1, 7200 +}; +static const sal_Int32 mso_sptDefault8100[] = +{ + 1, 8100 +}; +static const sal_Int32 mso_sptDefault9600[] = +{ + 1, 9600 +}; +static const sal_Int32 mso_sptDefault10800[] = +{ + 1, 10800 +}; +static const sal_Int32 mso_sptDefault12000[] = +{ + 1, 12000 +}; +static const sal_Int32 mso_sptDefault13500[] = +{ + 1, 13500 +}; +static const sal_Int32 mso_sptDefault16200[] = +{ + 1, 16200 +}; +static const sal_Int32 mso_sptDefault16200and5400[] = +{ + 2, 16200, 5400 +}; + +static 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 } +}; +static const sal_uInt16 mso_sptArcSegm[] = +{ + 0xa604, 0xab00, 0x0001, 0x6001, 0x8000, + 0xa604, 0xaa00, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptArcDefault[] = +{ + 2, 270, 0 +}; +static const SvxMSDffVertPair mso_sptStandardGluePoints[] = +{ + { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 21600, 10800 } +}; +static 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 } +}; +static const mso_CustomShape msoArc = +{ + const_cast(mso_sptArcVert), SAL_N_ELEMENTS( mso_sptArcVert ), + const_cast(mso_sptArcSegm), sizeof( mso_sptArcSegm ) >> 1, + const_cast(mso_sptArcCalc), SAL_N_ELEMENTS( mso_sptArcCalc ), + const_cast(mso_sptArcDefault), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptArcHandle), SAL_N_ELEMENTS( mso_sptArcHandle ) // handles +}; + +static const SvxMSDffVertPair mso_sptTextSimpleVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 } +}; +static const mso_CustomShape msoTextSimple = +{ + const_cast(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 +}; + +static const SvxMSDffVertPair mso_sptRectangleVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 } +}; +static const mso_CustomShape msoRectangle = +{ + const_cast(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 +}; + +static 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 } +}; +static const sal_uInt16 mso_sptRoundRectangleSegm[] = +{ + 0x4000, 0xa701, 0x0001, 0xa801, 0x0001, 0xa701, 0x0001, 0xa801, 0x6000, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptRoundRectangleTextRect[] = +{ + { { 3 MSO_I, 4 MSO_I }, { 5 MSO_I, 6 MSO_I } } +}; +static const SvxMSDffHandle mso_sptRoundRectangleHandle[] = +{ + { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED, + 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoRoundRectangle = +{ + const_cast(mso_sptRoundRectangleVert), SAL_N_ELEMENTS( mso_sptRoundRectangleVert ), + const_cast(mso_sptRoundRectangleSegm), sizeof( mso_sptRoundRectangleSegm ) >> 1, + const_cast(mso_sptRoundRectangleCalc), SAL_N_ELEMENTS( mso_sptRoundRectangleCalc ), + const_cast(mso_sptDefault3600), + const_cast(mso_sptRoundRectangleTextRect), SAL_N_ELEMENTS( mso_sptRoundRectangleTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptRoundRectangleHandle), SAL_N_ELEMENTS( mso_sptRoundRectangleHandle ) // handles +}; + +static const SvxMSDffVertPair mso_sptRightTriangleVert[] = +{ + { 0, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 } +}; +static const SvxMSDffTextRectangles mso_sptRightTriangleTextRect[] = +{ + { { 1900, 12700 }, { 12700, 19700 } } +}; +static const SvxMSDffVertPair mso_sptRightTriangleGluePoints[] = +{ + { 0, 0 }, { 0, 10800 }, { 0, 21600 }, { 10800, 21600 }, { 21600, 21600 }, { 10800, 10800 } +}; +static const mso_CustomShape msoRightTriangle = +{ + const_cast(mso_sptRightTriangleVert), SAL_N_ELEMENTS( mso_sptRightTriangleVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptRightTriangleTextRect), SAL_N_ELEMENTS( mso_sptRightTriangleTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptRightTriangleGluePoints), SAL_N_ELEMENTS( mso_sptRightTriangleGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptEllipseVert[] = +{ + { 10800, 10800 }, { 10800, 10800 }, { 0, 360 } +}; +static const sal_uInt16 mso_sptEllipseSegm[] = +{ + 0xa203, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptEllipseTextRect[] = +{ + { { 3163, 3163 }, { 18437, 18437 } } +}; +static const SvxMSDffVertPair mso_sptEllipseGluePoints[] = +{ + { 10800, 0 }, { 3163, 3163 }, { 0, 10800 }, { 3163, 18437 }, { 10800, 21600 }, { 18437, 18437 }, { 21600, 10800 }, { 18437, 3163 } +}; +static const mso_CustomShape msoEllipse = +{ + const_cast(mso_sptEllipseVert), SAL_N_ELEMENTS( mso_sptEllipseVert ), + const_cast(mso_sptEllipseSegm), sizeof( mso_sptEllipseSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptEllipseTextRect), SAL_N_ELEMENTS( mso_sptEllipseTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptParallelogramVert[] = // adjustment1 : 0 - 21600 +{ + { 0 MSO_I, 0 }, { 21600, 0 }, { 1 MSO_I, 21600 }, { 0, 21600 } +}; +static const sal_uInt16 mso_sptParallelogramSegm[] = +{ + 0x4000, 0x0003, 0x6001, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptParallelogramTextRect[] = +{ + { { 3 MSO_I, 3 MSO_I }, { 4 MSO_I, 4 MSO_I } } +}; +static 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 } +}; +static const SvxMSDffHandle mso_sptParallelogramHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0, 10800, 10800, 0, 21600, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoParallelogram = +{ + const_cast(mso_sptParallelogramVert), SAL_N_ELEMENTS( mso_sptParallelogramVert ), + const_cast(mso_sptParallelogramSegm), sizeof( mso_sptParallelogramSegm ) >> 1, + const_cast(mso_sptParallelogramCalc), SAL_N_ELEMENTS( mso_sptParallelogramCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptParallelogramTextRect), SAL_N_ELEMENTS( mso_sptParallelogramTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptParallelogramGluePoints), SAL_N_ELEMENTS( mso_sptParallelogramGluePoints ), + const_cast(mso_sptParallelogramHandle), SAL_N_ELEMENTS( mso_sptParallelogramHandle ) // handles +}; + +static const SvxMSDffVertPair mso_sptDiamondVert[] = +{ + { 10800, 0 }, { 21600, 10800 }, { 10800, 21600 }, { 0, 10800 }, { 10800, 0 } +}; +static const SvxMSDffTextRectangles mso_sptDiamondTextRect[] = +{ + { { 5400, 5400 }, { 16200, 16200 } } +}; +static const mso_CustomShape msoDiamond = +{ + const_cast(mso_sptDiamondVert), SAL_N_ELEMENTS( mso_sptDiamondVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptDiamondTextRect), SAL_N_ELEMENTS( mso_sptDiamondTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptTrapezoidVert[] = // adjustment1 : 0 - 10800 +{ + { 0, 0 }, { 21600, 0 }, {0 MSO_I, 21600 }, { 1 MSO_I, 21600 } +}; +static const sal_uInt16 mso_sptTrapezoidSegm[] = +{ + 0x4000, 0x0003, 0x6001, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptTrapezoidTextRect[] = +{ + { { 3 MSO_I, 3 MSO_I }, { 4 MSO_I, 4 MSO_I } } +}; +static const SvxMSDffVertPair mso_sptTrapezoidGluePoints[] = +{ + { 6 MSO_I, 10800 }, { 10800, 21600 }, { 5 MSO_I, 10800 }, { 10800, 0 } +}; +static const SvxMSDffHandle mso_sptTrapezoidHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 1, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoTrapezoid = +{ + const_cast(mso_sptTrapezoidVert), SAL_N_ELEMENTS( mso_sptTrapezoidVert ), + const_cast(mso_sptTrapezoidSegm), sizeof( mso_sptTrapezoidSegm ) >> 1, + const_cast(mso_sptTrapezoidCalc), SAL_N_ELEMENTS( mso_sptTrapezoidCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptTrapezoidTextRect), SAL_N_ELEMENTS( mso_sptTrapezoidTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptTrapezoidGluePoints), SAL_N_ELEMENTS( mso_sptTrapezoidGluePoints ), + const_cast(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 + +*/ + +static 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 } +}; +static const sal_uInt16 mso_sptOctagonSegm[] = +{ + 0x4000, 0x0007, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptOctagonDefault[] = +{ + 1, static_cast((21600 - ((M_SQRT2-1)*21600)) / 2) +}; +static const SvxMSDffTextRectangles mso_sptOctagonTextRect[] = +{ + { { 5 MSO_I, 6 MSO_I }, { 7 MSO_I, 8 MSO_I } } +}; +static const SvxMSDffHandle mso_sptOctagonHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoOctagon = +{ + const_cast(mso_sptOctagonVert), SAL_N_ELEMENTS( mso_sptOctagonVert ), + const_cast(mso_sptOctagonSegm), sizeof( mso_sptOctagonSegm ) >> 1, + const_cast(mso_sptOctagonCalc), SAL_N_ELEMENTS( mso_sptOctagonCalc ), + const_cast(mso_sptOctagonDefault), + const_cast(mso_sptOctagonTextRect), SAL_N_ELEMENTS( mso_sptOctagonTextRect ), + 21600, 21600, + 10800, 10800, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + const_cast(mso_sptOctagonHandle), SAL_N_ELEMENTS( mso_sptOctagonHandle ) // handles +}; + +static const SvxMSDffVertPair mso_sptIsocelesTriangleVert[] = // adjustment1 : 0 - 21600 +{ + { 0 MSO_I, 0 }, { 21600, 21600 }, { 0, 21600 } +}; +static const sal_uInt16 mso_sptIsocelesTriangleSegm[] = +{ + 0x4000, 0x0002, 0x6001, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptIsocelesTriangleTextRect[] = +{ + { { 1 MSO_I, 10800 }, { 2 MSO_I, 18000 } }, + { { 3 MSO_I, 7200 }, { 4 MSO_I, 21600 } } +}; +static const SvxMSDffVertPair mso_sptIsocelesTriangleGluePoints[] = +{ + { 0 MSO_I, 0 }, { 1 MSO_I, 10800 }, { 0, 21600 }, { 10800, 21600 }, { 21600, 21600 }, { 7 MSO_I, 10800 } +}; +static const SvxMSDffHandle mso_sptIsocelesTriangleHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0, 10800, 10800, 0, 21600, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoIsocelesTriangle = +{ + const_cast(mso_sptIsocelesTriangleVert), SAL_N_ELEMENTS( mso_sptIsocelesTriangleVert ), + const_cast(mso_sptIsocelesTriangleSegm), sizeof( mso_sptIsocelesTriangleSegm ) >> 1, + const_cast(mso_sptIsocelesTriangleCalc), SAL_N_ELEMENTS( mso_sptIsocelesTriangleCalc ), + const_cast(mso_sptDefault10800), + const_cast(mso_sptIsocelesTriangleTextRect), SAL_N_ELEMENTS( mso_sptIsocelesTriangleTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptIsocelesTriangleGluePoints), SAL_N_ELEMENTS( mso_sptIsocelesTriangleGluePoints ), + const_cast(mso_sptIsocelesTriangleHandle), SAL_N_ELEMENTS( mso_sptIsocelesTriangleHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptHexagonSegm[] = +{ + 0x4000, 0x0005, 0x6001, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptHexagonTextRect[] = +{ + { { 3 MSO_I, 3 MSO_I }, { 4 MSO_I, 4 MSO_I } } +}; +static const SvxMSDffHandle mso_sptHexagonHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoHexagon = +{ + const_cast(mso_sptHexagonVert), SAL_N_ELEMENTS( mso_sptHexagonVert ), + const_cast(mso_sptHexagonSegm), sizeof( mso_sptHexagonSegm ) >> 1, + const_cast(mso_sptHexagonCalc), SAL_N_ELEMENTS( mso_sptHexagonCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptHexagonTextRect), SAL_N_ELEMENTS( mso_sptHexagonTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + const_cast(mso_sptHexagonHandle), SAL_N_ELEMENTS( mso_sptHexagonHandle ) // handles +}; + +static const SvxMSDffVertPair mso_sptPentagonVert[] = +{ + { 10800, 0 }, { 0, 8260 }, { 4230, 21600 }, { 17370, 21600 }, + { 21600, 8260 }, { 10800, 0 } +}; +static const SvxMSDffTextRectangles mso_sptPentagonTextRect[] = +{ + { { 4230, 5080 }, { 17370, 21600 } } +}; +static const SvxMSDffVertPair mso_sptPentagonGluePoints[] = +{ + { 10800, 0 }, { 0, 8260 }, { 4230, 21600 }, { 10800, 21600 }, + { 17370, 21600 }, { 21600, 8260 } +}; +static const mso_CustomShape msoPentagon = +{ + const_cast(mso_sptPentagonVert), SAL_N_ELEMENTS( mso_sptPentagonVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptPentagonTextRect), SAL_N_ELEMENTS( mso_sptPentagonTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptPentagonGluePoints), SAL_N_ELEMENTS( mso_sptPentagonGluePoints ), + nullptr, 0 // handles +}; + +static 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 } +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptPlusTextRect[] = +{ + { { 1 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I } } +}; +static const SvxMSDffHandle mso_sptPlusHandle[] = +{ + { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED, + 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoPlus = +{ + const_cast(mso_sptPlusVert), SAL_N_ELEMENTS( mso_sptPlusVert ), + nullptr, 0, + const_cast(mso_sptPlusCalc), SAL_N_ELEMENTS( mso_sptPlusCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptPlusTextRect), SAL_N_ELEMENTS( mso_sptPlusTextRect ), + 21600, 21600, + 10800, 10800, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + const_cast(mso_sptPlusHandle), SAL_N_ELEMENTS( mso_sptPlusHandle ) // handles +}; + +static 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 +}; +static const sal_uInt16 mso_sptCanSegm[] = +{ + 0x4000, 0x2001, 0x0001, 0x2002, 0x0001, 0x2001, 0x6001, 0x8000, + 0x4000, 0x2004, 0x6001, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptCanTextRect[] = +{ + { { 0, 6 MSO_I }, { 88, 3 MSO_I } } +}; +static const SvxMSDffVertPair mso_sptCanGluePoints[] = +{ + { 44, 6 MSO_I }, { 44, 0 }, { 0, 10800 }, { 44, 21600 }, { 88, 10800 } +}; +static const SvxMSDffHandle mso_sptCanHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 7 + 3, 0x100, 44, 10800, MIN_INT32, 0x7fffffff, 0, 10800 } +}; +static const mso_CustomShape msoCan = +{ + const_cast(mso_sptCanVert), SAL_N_ELEMENTS( mso_sptCanVert ), + const_cast(mso_sptCanSegm), sizeof( mso_sptCanSegm ) >> 1, + const_cast(mso_sptCanCalc), SAL_N_ELEMENTS( mso_sptCanCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptCanTextRect), SAL_N_ELEMENTS( mso_sptCanTextRect ), + 88, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptCanGluePoints), SAL_N_ELEMENTS( mso_sptCanGluePoints ), + const_cast(mso_sptCanHandle), SAL_N_ELEMENTS( mso_sptCanHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptArrowSegm[] = +{ + 0x4000, 0x0006, 0x6001, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptArrowTextRect[] = +{ + { { 0, 0 MSO_I }, { 5 MSO_I, 2 MSO_I } } +}; +static const SvxMSDffHandle mso_sptArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0x101, 10800, 10800, 0, 21600, 0, 10800 } +}; +static const mso_CustomShape msoArrow = +{ + const_cast(mso_sptArrowVert), SAL_N_ELEMENTS( mso_sptArrowVert ), + const_cast(mso_sptArrowSegm), sizeof( mso_sptArrowSegm ) >> 1, + const_cast(mso_sptArrowCalc), SAL_N_ELEMENTS( mso_sptArrowCalc ), + const_cast(mso_sptDefault16200and5400), + const_cast(mso_sptArrowTextRect), SAL_N_ELEMENTS( mso_sptArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptArrowHandle), SAL_N_ELEMENTS( mso_sptArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptLeftArrowSegm[] = +{ + 0x4000, 0x0006, 0x6001, 0x8000 +}; +static const sal_Int32 mso_sptLeftArrowDefault[] = +{ + 2, 5400, 5400 +}; +static const SvxMSDffTextRectangles mso_sptLeftArrowTextRect[] = +{ + { { 7 MSO_I, 0 MSO_I }, { 21600, 2 MSO_I } } +}; +static const SvxMSDffHandle mso_sptLeftArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0x101, 10800, 10800, 0, 21600, 0, 10800 } +}; +static const mso_CustomShape msoLeftArrow = +{ + const_cast(mso_sptLeftArrowVert), SAL_N_ELEMENTS( mso_sptLeftArrowVert ), + const_cast(mso_sptLeftArrowSegm), sizeof( mso_sptLeftArrowSegm ) >> 1, + const_cast(mso_sptArrowCalc), SAL_N_ELEMENTS( mso_sptArrowCalc ), + const_cast(mso_sptLeftArrowDefault), + const_cast(mso_sptLeftArrowTextRect), SAL_N_ELEMENTS( mso_sptLeftArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptLeftArrowHandle), SAL_N_ELEMENTS( mso_sptLeftArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptDownArrowSegm[] = +{ + 0x4000, 0x0006, 0x6001, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptDownArrowTextRect[] = +{ + { { 0 MSO_I, 0 }, { 2 MSO_I, 5 MSO_I } } +}; +static const SvxMSDffHandle mso_sptDownArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x101, 0x100, 10800, 10800, 0, 10800, 0, 21600 } +}; +static const mso_CustomShape msoDownArrow = +{ + const_cast(mso_sptDownArrowVert), SAL_N_ELEMENTS( mso_sptDownArrowVert ), + const_cast(mso_sptDownArrowSegm), sizeof( mso_sptDownArrowSegm ) >> 1, + const_cast(mso_sptArrowCalc), SAL_N_ELEMENTS( mso_sptArrowCalc ), + const_cast(mso_sptDefault16200and5400), + const_cast(mso_sptDownArrowTextRect), SAL_N_ELEMENTS( mso_sptDownArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptDownArrowHandle), SAL_N_ELEMENTS( mso_sptDownArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptUpArrowSegm[] = +{ + 0x4000, 0x0006, 0x6001, 0x8000 +}; +static const sal_Int32 mso_sptUpArrowDefault[] = +{ + 2, 5400, 5400 +}; +static const SvxMSDffTextRectangles mso_sptUpArrowTextRect[] = +{ + { { 0 MSO_I, 7 MSO_I }, { 2 MSO_I, 21600 } } +}; +static const SvxMSDffHandle mso_sptUpArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x101, 0x100, 10800, 10800, 0, 10800, 0, 21600 } +}; +static const mso_CustomShape msoUpArrow = +{ + const_cast(mso_sptUpArrowVert), SAL_N_ELEMENTS( mso_sptUpArrowVert ), + const_cast(mso_sptUpArrowSegm), sizeof( mso_sptUpArrowSegm ) >> 1, + const_cast(mso_sptArrowCalc), SAL_N_ELEMENTS( mso_sptArrowCalc ), + const_cast(mso_sptUpArrowDefault), + const_cast(mso_sptUpArrowTextRect), SAL_N_ELEMENTS( mso_sptUpArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptUpArrowHandle), SAL_N_ELEMENTS( mso_sptUpArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptLeftRightArrowSegm[] = +{ + 0x4000, 0x0009, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptLeftRightArrowDefault[] = +{ + 2, 4300, 5400 +}; +static const SvxMSDffTextRectangles mso_sptLeftRightArrowTextRect[] = +{ + { { 5 MSO_I, 1 MSO_I }, { 6 MSO_I, 3 MSO_I } } +}; +static const SvxMSDffHandle mso_sptLeftRightArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0x101, 10800, 10800, 0, 10800, 0, 10800 } +}; +static const mso_CustomShape msoLeftRightArrow = +{ + const_cast(mso_sptLeftRightArrowVert), SAL_N_ELEMENTS( mso_sptLeftRightArrowVert ), + const_cast(mso_sptLeftRightArrowSegm), sizeof( mso_sptLeftRightArrowSegm ) >> 1, + const_cast(mso_sptDoubleArrowCalc), SAL_N_ELEMENTS( mso_sptDoubleArrowCalc ), + const_cast(mso_sptLeftRightArrowDefault), + const_cast(mso_sptLeftRightArrowTextRect), SAL_N_ELEMENTS( mso_sptLeftRightArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptLeftRightArrowHandle), SAL_N_ELEMENTS( mso_sptLeftRightArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptUpDownArrowSegm[] = +{ + 0x4000, 0x0009, 0x6001, 0x8000 +}; +static const sal_Int32 mso_sptUpDownArrowDefault[] = +{ + 2, 5400, 4300 +}; +static const SvxMSDffTextRectangles mso_sptUpDownArrowTextRect[] = +{ + { { 0 MSO_I, 8 MSO_I }, { 2 MSO_I, 9 MSO_I } } +}; +static const SvxMSDffHandle mso_sptUpDownArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0x101, 10800, 10800, 0, 10800, 0, 10800 } +}; +static const mso_CustomShape msoUpDownArrow = +{ + const_cast(mso_sptUpDownArrowVert), SAL_N_ELEMENTS( mso_sptUpDownArrowVert ), + const_cast(mso_sptUpDownArrowSegm), sizeof( mso_sptUpDownArrowSegm ) >> 1, + const_cast(mso_sptDoubleArrowCalc), SAL_N_ELEMENTS( mso_sptDoubleArrowCalc ), + const_cast(mso_sptUpDownArrowDefault), + const_cast(mso_sptUpDownArrowTextRect), SAL_N_ELEMENTS( mso_sptUpDownArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptUpDownArrowHandle), SAL_N_ELEMENTS( mso_sptUpDownArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptQuadArrowSegm[] = +{ + 0x4000, 0x0017, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptQuadArrowDefault[] = +{ + 3, 6500, 8600, 4300 +}; +static const SvxMSDffTextRectangles mso_sptQuadArrowTextRect[] = // todo +{ + { { 0, 0 }, { 21600, 21600 } } +}; +static 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 } +}; +static const mso_CustomShape msoQuadArrow = +{ + const_cast(mso_sptQuadArrowVert), SAL_N_ELEMENTS( mso_sptQuadArrowVert ), + const_cast(mso_sptQuadArrowSegm), sizeof( mso_sptQuadArrowSegm ) >> 1, + const_cast(mso_sptQuadArrowCalc), SAL_N_ELEMENTS( mso_sptQuadArrowCalc ), + const_cast(mso_sptQuadArrowDefault), + const_cast(mso_sptQuadArrowTextRect), SAL_N_ELEMENTS( mso_sptQuadArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptQuadArrowHandle), SAL_N_ELEMENTS( mso_sptQuadArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptLeftRightUpArrowSegm[] = +{ + 0x4000, 0x0010, 0x6001, 0x8000 +}; +static 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 +}; +static const sal_Int32 mso_sptLeftRightUpArrowDefault[] = +{ + 3, 6500, 8600, 6200 +}; +static const SvxMSDffTextRectangles mso_sptLeftRightUpArrowTextRect[] = // todo +{ + { { 0, 0 }, { 21600, 21600 } } +}; +static 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 } +}; +static const mso_CustomShape msoLeftRightUpArrow = +{ + const_cast(mso_sptLeftRightUpArrowVert), SAL_N_ELEMENTS( mso_sptLeftRightUpArrowVert ), + const_cast(mso_sptLeftRightUpArrowSegm), sizeof( mso_sptLeftRightUpArrowSegm ) >> 1, + const_cast(mso_sptLeftRightUpArrowCalc), SAL_N_ELEMENTS( mso_sptLeftRightUpArrowCalc ), + const_cast(mso_sptLeftRightUpArrowDefault), + const_cast(mso_sptLeftRightUpArrowTextRect), SAL_N_ELEMENTS( mso_sptLeftRightUpArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptLeftRightUpArrowHandle), SAL_N_ELEMENTS( mso_sptLeftRightUpArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptBentArrowSegm[] = +{ + 0x4000, 0x0001, 0xa801, 0x0006, 0xa701, 0x0001, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptBentArrowDefault[] = +{ + 2, 15100, 2900 +}; +static const SvxMSDffTextRectangles mso_sptBentArrowTextRect[] = // todo +{ + { { 0, 0 }, { 21600, 21600 } } +}; +static const SvxMSDffHandle mso_sptBentArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0x101, 10800, 10800, 12427, 21600, 0, 6079 } +}; +static const mso_CustomShape msoBentArrow = +{ + const_cast(mso_sptBentArrowVert), SAL_N_ELEMENTS( mso_sptBentArrowVert ), + const_cast(mso_sptBentArrowSegm), sizeof( mso_sptBentArrowSegm ) >> 1, + const_cast(mso_sptBentArrowCalc), SAL_N_ELEMENTS( mso_sptBentArrowCalc ), + const_cast(mso_sptBentArrowDefault), + const_cast(mso_sptBentArrowTextRect), SAL_N_ELEMENTS( mso_sptBentArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptBentArrowHandle), SAL_N_ELEMENTS( mso_sptBentArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptUturnArrowSegm[] = +{ + 0x4000, 0x0001, 0x2002, 0x0004, 0x2002, 0x0001, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptUturnArrowTextRect[] = +{ + { { 0, 8280 }, { 6110, 21600 } } +}; +static const mso_CustomShape msoUturnArrow = +{ + const_cast(mso_sptUturnArrowVert), SAL_N_ELEMENTS( mso_sptUturnArrowVert ), + const_cast(mso_sptUturnArrowSegm), sizeof( mso_sptUturnArrowSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptUturnArrowTextRect), SAL_N_ELEMENTS( mso_sptUturnArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + nullptr, 0 // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptLeftUpArrowSegm[] = +{ + 0x4000, 0x000b, 0x6001, 0x8000 +}; +static 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 +}; +static const sal_Int32 mso_sptLeftUpArrowDefault[] = +{ + 3, 9340, 18500, 6200 +}; +static 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 } } +}; +static 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 } +}; +static const mso_CustomShape msoLeftUpArrow = +{ + const_cast(mso_sptLeftUpArrowVert), SAL_N_ELEMENTS( mso_sptLeftUpArrowVert ), + const_cast(mso_sptLeftUpArrowSegm), sizeof( mso_sptLeftUpArrowSegm ) >> 1, + const_cast(mso_sptLeftUpArrowCalc), SAL_N_ELEMENTS( mso_sptLeftUpArrowCalc ), + const_cast(mso_sptLeftUpArrowDefault), + const_cast(mso_sptLeftUpArrowTextRect), SAL_N_ELEMENTS( mso_sptLeftUpArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptLeftUpArrowHandle), SAL_N_ELEMENTS( mso_sptLeftUpArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptBentUpArrowSegm[] = +{ + 0x4000, 0x0008, 0x6001, 0x8000 +}; +static 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 +}; +static const sal_Int32 mso_sptBentUpArrowDefault[] = +{ + 3, 9340, 18500, 7200 +}; +static 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 } } +}; +static 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 } +}; +static const mso_CustomShape msoBentUpArrow = +{ + const_cast(mso_sptBentUpArrowVert), SAL_N_ELEMENTS( mso_sptBentUpArrowVert ), + const_cast(mso_sptBentUpArrowSegm), sizeof( mso_sptBentUpArrowSegm ) >> 1, + const_cast(mso_sptBentUpArrowCalc), SAL_N_ELEMENTS( mso_sptBentUpArrowCalc ), + const_cast(mso_sptBentUpArrowDefault), + const_cast(mso_sptBentUpArrowTextRect), SAL_N_ELEMENTS( mso_sptBentUpArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptBentUpArrowHandle), SAL_N_ELEMENTS( mso_sptBentUpArrowHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptCurvedRightSegm[] = +{ + 0xa408, + 0x0003, + 0xa508, + 0x6000, + 0x8000, + 0xa404, + 0xa304, + 0xa504, + 0x6000, + 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptCurvedRightDefault[] = +{ + 3, 12960, 19440, 14400 +}; +static const SvxMSDffTextRectangles mso_sptCurvedRightTextRect[] = +{ + { { 47 MSO_I, 45 MSO_I }, { 48 MSO_I, 46 MSO_I } } +}; +static 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 } +}; +static 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 } +}; +static const mso_CustomShape msoCurvedRightArrow = +{ + const_cast(mso_sptCurvedRightVert), SAL_N_ELEMENTS( mso_sptCurvedRightVert ), + const_cast(mso_sptCurvedRightSegm), sizeof( mso_sptCurvedRightSegm ) >> 1, + const_cast(mso_sptCurvedRightCalc), SAL_N_ELEMENTS( mso_sptCurvedRightCalc ), + const_cast(mso_sptCurvedRightDefault), + const_cast(mso_sptCurvedRightTextRect), SAL_N_ELEMENTS( mso_sptCurvedRightTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptCurvedRightGluePoints), SAL_N_ELEMENTS( mso_sptCurvedRightGluePoints ), + const_cast(mso_sptCurvedRightHandles), SAL_N_ELEMENTS( mso_sptCurvedRightHandles ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptCurvedDownSegm[] = +{ + 0xa608, + 0x0003, + 0xa308, + 0x6000, + 0x8000, + 0xa604, + 0xa504, + 0xa304, + 0x6000, + 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptCurvedDownTextRect[] = +{ + { { 45 MSO_I, 47 MSO_I }, { 46 MSO_I, 48 MSO_I } } +}; +static 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 } +}; +static 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 } +}; + +static const mso_CustomShape msoCurvedDownArrow = +{ + const_cast(mso_sptCurvedDownVert), SAL_N_ELEMENTS( mso_sptCurvedDownVert ), + const_cast(mso_sptCurvedDownSegm), sizeof( mso_sptCurvedDownSegm ) >> 1, + const_cast(mso_sptCurvedRightCalc), SAL_N_ELEMENTS( mso_sptCurvedRightCalc ), + const_cast(mso_sptCurvedRightDefault), + const_cast(mso_sptCurvedDownTextRect), SAL_N_ELEMENTS( mso_sptCurvedDownTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptCurvedDownGluePoints), SAL_N_ELEMENTS( mso_sptCurvedDownGluePoints ), + const_cast(mso_sptCurvedDownHandles), SAL_N_ELEMENTS( mso_sptCurvedDownHandles ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptCurvedUpSegm[] = +{ + 0xa408, + 0x0003, + 0xa508, + 0x6000, + 0x8000, + 0xa404, + 0xa508, + 0xa504, + 0x6000, + 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptCurvedUpDefault[] = +{ + 3, 12960, 19440, 7200 +}; +static const SvxMSDffTextRectangles mso_sptCurvedUpTextRect[] = +{ + { { 41 MSO_I, 43 MSO_I }, { 42 MSO_I, 44 MSO_I } } +}; +static 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 } +}; +static 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 } +}; +static const mso_CustomShape msoCurvedUpArrow = +{ + const_cast(mso_sptCurvedUpVert), SAL_N_ELEMENTS( mso_sptCurvedUpVert ), + const_cast(mso_sptCurvedUpSegm), sizeof( mso_sptCurvedUpSegm ) >> 1, + const_cast(mso_sptCurvedUpCalc), SAL_N_ELEMENTS( mso_sptCurvedUpCalc ), + const_cast(mso_sptCurvedUpDefault), + const_cast(mso_sptCurvedUpTextRect), SAL_N_ELEMENTS( mso_sptCurvedUpTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptCurvedUpGluePoints), SAL_N_ELEMENTS( mso_sptCurvedUpGluePoints ), + const_cast(mso_sptCurvedUpHandles), SAL_N_ELEMENTS( mso_sptCurvedUpHandles ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptCurvedLeftSegm[] = +{ + 0xa608, + 0x0003, + 0xa308, + 0x6000, + 0x8000, + 0xa604, + 0xa308, + 0x6000, + 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptCurvedLeftTextRect[] = +{ + { { 43 MSO_I, 41 MSO_I }, { 44 MSO_I, 42 MSO_I } } +}; +static 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 } +}; +static 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 } +}; +static const mso_CustomShape msoCurvedLeftArrow = +{ + const_cast(mso_sptCurvedLeftVert), SAL_N_ELEMENTS( mso_sptCurvedLeftVert ), + const_cast(mso_sptCurvedLeftSegm), sizeof( mso_sptCurvedLeftSegm ) >> 1, + const_cast(mso_sptCurvedUpCalc), SAL_N_ELEMENTS( mso_sptCurvedUpCalc ), + const_cast(mso_sptCurvedUpDefault), + const_cast(mso_sptCurvedLeftTextRect), SAL_N_ELEMENTS( mso_sptCurvedLeftTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptCurvedLeftGluePoints), SAL_N_ELEMENTS( mso_sptCurvedLeftGluePoints ), + const_cast(mso_sptCurvedLeftHandles), SAL_N_ELEMENTS( mso_sptCurvedLeftHandles ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptStripedRightArrowSegm[] = +{ + 0x4000, 0x0006, 0x6001, 0x8000, + 0x4000, 0x0003, 0x6001, 0x8000, + 0x4000, 0x0003, 0x6001, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptStripedRightArrowTextRect[] = +{ + { { 3375, 0 MSO_I }, { 5 MSO_I, 2 MSO_I } } +}; +static const SvxMSDffHandle mso_sptStripedRightArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0x101, 10800, 10800, 3375, 21600, 0, 10800 } +}; +static const mso_CustomShape msoStripedRightArrow = +{ + const_cast(mso_sptStripedRightArrowVert), SAL_N_ELEMENTS( mso_sptStripedRightArrowVert ), + const_cast(mso_sptStripedRightArrowSegm), sizeof( mso_sptStripedRightArrowSegm ) >> 1, + const_cast(mso_sptStripedRightArrowCalc), SAL_N_ELEMENTS( mso_sptStripedRightArrowCalc ), + const_cast(mso_sptDefault16200and5400), + const_cast(mso_sptStripedRightArrowTextRect), SAL_N_ELEMENTS( mso_sptStripedRightArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptStripedRightArrowHandle), SAL_N_ELEMENTS( mso_sptStripedRightArrowHandle ) +}; + +static 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 } +}; +static 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 }} +}; +static const SvxMSDffTextRectangles mso_sptNotchedRightArrowTextRect[] = // todo +{ + { { 5 MSO_I, 1 MSO_I }, { 6 MSO_I, 2 MSO_I } } +}; +static const SvxMSDffHandle mso_sptNotchedRightArrowHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0x101, 10800, 10800, 0, 21600, 0, 10800 } +}; +static const mso_CustomShape msoNotchedRightArrow = +{ + const_cast(mso_sptNotchedRightArrowVert), SAL_N_ELEMENTS( mso_sptNotchedRightArrowVert ), + nullptr, 0, + const_cast(mso_sptNotchedRightArrowCalc), SAL_N_ELEMENTS( mso_sptNotchedRightArrowCalc ), + const_cast(mso_sptDefault16200and5400), + const_cast(mso_sptNotchedRightArrowTextRect), SAL_N_ELEMENTS( mso_sptNotchedRightArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptNotchedRightArrowHandle), SAL_N_ELEMENTS( mso_sptNotchedRightArrowHandle ) +}; + +static const SvxMSDffVertPair mso_sptHomePlateVert[] = // adjustment1 : x 0 - 21600 +{ + { 0, 0 }, { 0 MSO_I, 0 }, { 21600, 10800 }, { 0 MSO_I, 21600 }, + { 0, 21600 } +}; +static const sal_uInt16 mso_sptHomePlateSegm[] = +{ + 0x4000, 0x0004, 0x6001, 0x8000 +}; +static const SvxMSDffCalculationData mso_sptHomePlateCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } } +}; +static const sal_Int32 mso_sptHomePlateDefault[] = +{ + 1, 16200 +}; +static const SvxMSDffTextRectangles mso_sptHomePlateTextRect[] = // todo +{ + { { 0, 0 }, { 21600, 21600 } } +}; +static const SvxMSDffHandle mso_sptHomePlateHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0, 10800, 10800, 0, 21600, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoHomePlate = +{ + const_cast(mso_sptHomePlateVert), SAL_N_ELEMENTS( mso_sptHomePlateVert ), + const_cast(mso_sptHomePlateSegm), sizeof( mso_sptHomePlateSegm ) >> 1, + const_cast(mso_sptHomePlateCalc), SAL_N_ELEMENTS( mso_sptHomePlateCalc ), + const_cast(mso_sptHomePlateDefault), + const_cast(mso_sptHomePlateTextRect), SAL_N_ELEMENTS( mso_sptHomePlateTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptHomePlateHandle), SAL_N_ELEMENTS( mso_sptHomePlateHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptChevronSegm[] = +{ + 0x4000, 0x0005, 0x6001, 0x8000 +}; +static const SvxMSDffCalculationData mso_sptChevronCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, + { 0x8000, { 21600, 0, 0x0400 } } +}; +static const sal_Int32 mso_sptChevronDefault[] = +{ + 1, 16200 +}; +static const SvxMSDffTextRectangles mso_sptChevronTextRect[] = // todo +{ + { { 0, 0 }, { 21600, 21600 } } +}; +static const SvxMSDffHandle mso_sptChevronHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0, 10800, 10800, 0, 21600, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoChevron = +{ + const_cast(mso_sptChevronVert), SAL_N_ELEMENTS( mso_sptChevronVert ), + const_cast(mso_sptChevronSegm), sizeof( mso_sptChevronSegm ) >> 1, + const_cast(mso_sptChevronCalc), SAL_N_ELEMENTS( mso_sptChevronCalc ), + const_cast(mso_sptChevronDefault), + const_cast(mso_sptChevronTextRect), SAL_N_ELEMENTS( mso_sptChevronTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptChevronHandle), SAL_N_ELEMENTS( mso_sptChevronHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptRightArrowCalloutSegm[] = +{ + 0x4000, 0x000a, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptRightArrowCalloutDefault[] = +{ + 4, 14400, 5400, 18000, 8100 +}; +static const SvxMSDffTextRectangles mso_sptRightArrowCalloutTextRect[] = +{ + { { 0, 0 }, { 0 MSO_I, 21600 } } +}; +static 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 } +}; +static const mso_CustomShape msoRightArrowCallout = +{ + const_cast(mso_sptRightArrowCalloutVert), SAL_N_ELEMENTS( mso_sptRightArrowCalloutVert ), + const_cast(mso_sptRightArrowCalloutSegm), sizeof( mso_sptRightArrowCalloutSegm ) >> 1, + const_cast(mso_sptRightArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptRightArrowCalloutCalc ), + const_cast(mso_sptRightArrowCalloutDefault), + const_cast(mso_sptRightArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptRightArrowCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptRightArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptRightArrowCalloutHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptLeftArrowCalloutSegm[] = +{ + 0x4000, 0x000a, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptLeftArrowCalloutDefault[] = +{ + 4, 7200, 5400, 3600, 8100 +}; +static const SvxMSDffTextRectangles mso_sptLeftArrowCalloutTextRect[] = +{ + { { 0 MSO_I, 0 }, { 21600, 21600 } } +}; +static 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 } +}; +static const mso_CustomShape msoLeftArrowCallout = +{ + const_cast(mso_sptLeftArrowCalloutVert), SAL_N_ELEMENTS( mso_sptLeftArrowCalloutVert ), + const_cast(mso_sptLeftArrowCalloutSegm), sizeof( mso_sptLeftArrowCalloutSegm ) >> 1, + const_cast(mso_sptLeftArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptLeftArrowCalloutCalc ), + const_cast(mso_sptLeftArrowCalloutDefault), + const_cast(mso_sptLeftArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptLeftArrowCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptLeftArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptLeftArrowCalloutHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptUpArrowCalloutSegm[] = +{ + 0x4000, 0x000a, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptUpArrowCalloutDefault[] = +{ + 4, 7200, 5400, 3600, 8100 +}; +static const SvxMSDffTextRectangles mso_sptUpArrowCalloutTextRect[] = +{ + { { 0, 0 MSO_I }, { 21600, 21600 } } +}; +static 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 } +}; +static const mso_CustomShape msoUpArrowCallout = +{ + const_cast(mso_sptUpArrowCalloutVert), SAL_N_ELEMENTS( mso_sptUpArrowCalloutVert ), + const_cast(mso_sptUpArrowCalloutSegm), sizeof( mso_sptUpArrowCalloutSegm ) >> 1, + const_cast(mso_sptUpArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptUpArrowCalloutCalc ), + const_cast(mso_sptUpArrowCalloutDefault), + const_cast(mso_sptUpArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptUpArrowCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptUpArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptUpArrowCalloutHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptDownArrowCalloutSegm[] = +{ + 0x4000, 0x000a, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptDownArrowCalloutDefault[] = +{ + 4, 14400, 5400, 18000, 8100 +}; +static const SvxMSDffTextRectangles mso_sptDownArrowCalloutTextRect[] = +{ + { { 0, 0 }, { 21600, 0 MSO_I } } +}; +static 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 } +}; +static const mso_CustomShape msoDownArrowCallout = +{ + const_cast(mso_sptDownArrowCalloutVert), SAL_N_ELEMENTS( mso_sptDownArrowCalloutVert ), + const_cast(mso_sptDownArrowCalloutSegm), sizeof( mso_sptDownArrowCalloutSegm ) >> 1, + const_cast(mso_sptDownArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptDownArrowCalloutCalc ), + const_cast(mso_sptDownArrowCalloutDefault), + const_cast(mso_sptDownArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptDownArrowCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptDownArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptDownArrowCalloutHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptLeftRightArrowCalloutSegm[] = +{ + 0x4000, 0x0011, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptLeftRightArrowCalloutDefault[] = +{ + 4, 5400, 5500, 2700, 8100 +}; +static const SvxMSDffTextRectangles mso_sptLeftRightArrowCalloutTextRect[] = +{ + { { 0 MSO_I, 0 }, { 4 MSO_I, 21600 } } +}; +static 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 } +}; +static const mso_CustomShape msoLeftRightArrowCallout = +{ + const_cast(mso_sptLeftRightArrowCalloutVert), SAL_N_ELEMENTS( mso_sptLeftRightArrowCalloutVert ), + const_cast(mso_sptLeftRightArrowCalloutSegm), sizeof( mso_sptLeftRightArrowCalloutSegm ) >> 1, + const_cast(mso_sptLeftRightArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptLeftRightArrowCalloutCalc ), + const_cast(mso_sptLeftRightArrowCalloutDefault), + const_cast(mso_sptLeftRightArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptLeftRightArrowCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptLeftRightArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptLeftRightArrowCalloutHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptUpDownArrowCalloutSegm[] = +{ + 0x4000, 0x0011, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptUpDownArrowCalloutDefault[] = +{ + 4, 5400, 5500, 2700, 8100 +}; +static const SvxMSDffTextRectangles mso_sptUpDownArrowCalloutTextRect[] = +{ + { { 0, 0 MSO_I }, { 21600, 4 MSO_I } } +}; +static 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 } +}; +static const mso_CustomShape msoUpDownArrowCallout = +{ + const_cast(mso_sptUpDownArrowCalloutVert), SAL_N_ELEMENTS( mso_sptUpDownArrowCalloutVert ), + const_cast(mso_sptUpDownArrowCalloutSegm), sizeof( mso_sptUpDownArrowCalloutSegm ) >> 1, + const_cast(mso_sptUpDownArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptUpDownArrowCalloutCalc ), + const_cast(mso_sptUpDownArrowCalloutDefault), + const_cast(mso_sptUpDownArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptUpDownArrowCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptUpDownArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptUpDownArrowCalloutHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptQuadArrowCalloutSegm[] = +{ + 0x4000, 0x001f, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptQuadArrowCalloutDefault[] = +{ + 4, 5400, 8100, 2700, 9400 +}; +static const SvxMSDffTextRectangles mso_sptQuadArrowCalloutTextRect[] = +{ + { { 0 MSO_I, 0 MSO_I }, { 4 MSO_I, 4 MSO_I } } +}; +static 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 } +}; +static const mso_CustomShape msoQuadArrowCallout = +{ + const_cast(mso_sptQuadArrowCalloutVert), SAL_N_ELEMENTS( mso_sptQuadArrowCalloutVert ), + const_cast(mso_sptQuadArrowCalloutSegm), sizeof( mso_sptQuadArrowCalloutSegm ) >> 1, + const_cast(mso_sptQuadArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptQuadArrowCalloutCalc ), + const_cast(mso_sptQuadArrowCalloutDefault), + const_cast(mso_sptQuadArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptQuadArrowCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptQuadArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptQuadArrowCalloutHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptCircularArrowSegm[] = +{ + 0xa404, 0xa504, 0x0003, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptCircularArrowDefault[] = +{ + 3, 180, 0, 5500 +}; +static const SvxMSDffTextRectangles mso_sptCircularArrowTextRect[] = // todo +{ + { { 0, 0 }, { 21600, 21600 } } +}; +static 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 } +}; +static const mso_CustomShape msoCircularArrow = +{ + const_cast(mso_sptCircularArrowVert), SAL_N_ELEMENTS( mso_sptCircularArrowVert ), + const_cast(mso_sptCircularArrowSegm), sizeof( mso_sptCircularArrowSegm ) >> 1, + const_cast(mso_sptCircularArrowCalc), SAL_N_ELEMENTS( mso_sptCircularArrowCalc ), + const_cast(mso_sptCircularArrowDefault), + const_cast(mso_sptCircularArrowTextRect), SAL_N_ELEMENTS( mso_sptCircularArrowTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCircularArrowHandle), SAL_N_ELEMENTS( mso_sptCircularArrowHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptCubeSegm[] = +{ + 0x4000, 0x0005, 0x6001, 0x8000, + 0x4000, 0x0003, 0x6001, 0x8000, + 0x4000, 0x0003, 0x6001, 0x8000 +}; +static 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 +}; +static const SvxMSDffTextRectangles mso_sptCubeTextRect[] = +{ + { { 0, 1 MSO_I }, { 4 MSO_I, 12 MSO_I } } +}; +static const SvxMSDffHandle mso_sptCubeHandle[] = +{ + { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 21600 } +}; +static 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 } +}; +static const mso_CustomShape msoCube = +{ + const_cast(mso_sptCubeVert), SAL_N_ELEMENTS( mso_sptCubeVert ), + const_cast(mso_sptCubeSegm), sizeof( mso_sptCubeSegm ) >> 1, + const_cast(mso_sptCubeCalc), SAL_N_ELEMENTS( mso_sptCubeCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptCubeTextRect), SAL_N_ELEMENTS( mso_sptCubeTextRect ), + 21600, 21600, + 10800, 10800, + const_cast(mso_sptCubeGluePoints), SAL_N_ELEMENTS( mso_sptCubeGluePoints ), + const_cast(mso_sptCubeHandle), SAL_N_ELEMENTS( mso_sptCubeHandle ) +}; + +static 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 } +}; +static 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 +}; +static const SvxMSDffCalculationData mso_sptBevelCalc[] = +{ + { 0x2001, { DFF_Prop_adjustValue, 21599, 21600 } }, + { 0xa000, { DFF_Prop_geoRight, 0, 0x400 } }, + { 0xa000, { DFF_Prop_geoBottom, 0, 0x400 } } +}; + +static const SvxMSDffTextRectangles mso_sptBevelTextRect[] = +{ + { { 0 MSO_I, 0 MSO_I }, { 1 MSO_I, 2 MSO_I } } +}; +static const SvxMSDffHandle mso_sptBevelHandle[] = +{ + { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED, + 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoBevel = +{ + const_cast(mso_sptBevelVert), SAL_N_ELEMENTS( mso_sptBevelVert ), + const_cast(mso_sptBevelSegm), sizeof( mso_sptBevelSegm ) >> 1, + const_cast(mso_sptBevelCalc), SAL_N_ELEMENTS( mso_sptBevelCalc ), + const_cast(mso_sptDefault2700), + const_cast(mso_sptBevelTextRect), SAL_N_ELEMENTS( mso_sptBevelTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptBevelHandle), SAL_N_ELEMENTS( mso_sptBevelHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptFoldedCornerSegm[] = +{ + 0x4000, 0x0004, 0x6001, 0x8000, + 0x4000, 0x0001, 0x2001, 0x6001, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptFoldedCornerDefault[] = +{ + 1, 18900 +}; +static const SvxMSDffTextRectangles mso_sptFoldedCornerTextRect[] = +{ + { { 0, 0 }, { 21600, 11 MSO_I } } +}; +static const SvxMSDffHandle mso_sptFoldedCornerHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 1, 10800, 10800, 10800, 21600, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoFoldedCorner = +{ + const_cast(mso_sptFoldedCornerVert), SAL_N_ELEMENTS( mso_sptFoldedCornerVert ), + const_cast(mso_sptFoldedCornerSegm), sizeof( mso_sptFoldedCornerSegm ) >> 1, + const_cast(mso_sptFoldedCornerCalc), SAL_N_ELEMENTS( mso_sptFoldedCornerCalc ), + const_cast(mso_sptFoldedCornerDefault), + const_cast(mso_sptFoldedCornerTextRect), SAL_N_ELEMENTS( mso_sptFoldedCornerTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + const_cast(mso_sptFoldedCornerHandle), SAL_N_ELEMENTS( mso_sptFoldedCornerHandle ) +}; + +static 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 } +}; +static 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 +}; +static const SvxMSDffCalculationData mso_sptActionButtonBlankCalc[] = +{ + { 0x2001, { DFF_Prop_adjustValue, 21599, 21600 } }, + { 0xa000, { DFF_Prop_geoRight, 0, 0x400 } }, + { 0xa000, { DFF_Prop_geoBottom, 0, 0x400 } } +}; +static const SvxMSDffTextRectangles mso_sptActionButtonBlankTextRect[] = +{ + { { 0 MSO_I, 0 MSO_I }, { 1 MSO_I, 2 MSO_I } } +}; +static const SvxMSDffHandle mso_sptButtonHandle[] = +{ + { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED, + 0x100, 0, 10800, 10800, 0, 5400, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoActionButtonBlank = +{ + const_cast(mso_sptActionButtonBlankVert), SAL_N_ELEMENTS( mso_sptActionButtonBlankVert ), + const_cast(mso_sptActionButtonBlankSegm), sizeof( mso_sptActionButtonBlankSegm ) >> 1, + const_cast(mso_sptActionButtonBlankCalc), SAL_N_ELEMENTS( mso_sptActionButtonBlankCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonBlankTextRect), SAL_N_ELEMENTS( mso_sptActionButtonBlankTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static const SvxMSDffTextRectangles mso_sptActionButtonTextRect[] = +{ + { { 1 MSO_I, 2 MSO_I }, { 3 MSO_I, 4 MSO_I } } +}; +static 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 } + +}; +static 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 +}; +static 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 + +}; +static const mso_CustomShape msoActionButtonHome = +{ + const_cast(mso_sptActionButtonHomeVert), SAL_N_ELEMENTS( mso_sptActionButtonHomeVert ), + const_cast(mso_sptActionButtonHomeSegm), sizeof( mso_sptActionButtonHomeSegm ) >> 1, + const_cast(mso_sptActionButtonHomeCalc), SAL_N_ELEMENTS( mso_sptActionButtonHomeCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const mso_CustomShape msoActionButtonHelp = +{ + const_cast(mso_sptActionButtonHelpVert), SAL_N_ELEMENTS( mso_sptActionButtonHelpVert ), + const_cast(mso_sptActionButtonHelpSegm), sizeof( mso_sptActionButtonHelpSegm ) >> 1, + const_cast(mso_sptActionButtonHelpCalc), SAL_N_ELEMENTS( mso_sptActionButtonHelpCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static 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 +}; +static 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 + +}; +static const mso_CustomShape msoActionButtonInformation = +{ + const_cast(mso_sptActionButtonInformationVert), SAL_N_ELEMENTS( mso_sptActionButtonInformationVert ), + const_cast(mso_sptActionButtonInformationSegm), sizeof( mso_sptActionButtonInformationSegm ) >> 1, + const_cast(mso_sptActionButtonInformationCalc), SAL_N_ELEMENTS( mso_sptActionButtonInformationCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const mso_CustomShape msoActionButtonBackPrevious = +{ + const_cast(mso_sptActionButtonBackPreviousVert), SAL_N_ELEMENTS( mso_sptActionButtonBackPreviousVert ), + const_cast(mso_sptActionButtonForwardBackSegm), sizeof( mso_sptActionButtonForwardBackSegm ) >> 1, + const_cast(mso_sptActionButtonForwardBackCalc), SAL_N_ELEMENTS( mso_sptActionButtonForwardBackCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static const mso_CustomShape msoActionButtonForwardNext = +{ + const_cast(mso_sptActionButtonForwardNextVert), SAL_N_ELEMENTS( mso_sptActionButtonForwardNextVert ), + const_cast(mso_sptActionButtonForwardBackSegm), sizeof( mso_sptActionButtonForwardBackSegm ) >> 1, + const_cast(mso_sptActionButtonForwardBackCalc), SAL_N_ELEMENTS( mso_sptActionButtonForwardBackCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const mso_CustomShape msoActionButtonBeginning = +{ + const_cast(mso_sptActionButtonBeginningVert), SAL_N_ELEMENTS( mso_sptActionButtonBeginningVert ), + const_cast(mso_sptActionButtonBeginningEndSegm), sizeof( mso_sptActionButtonBeginningEndSegm ) >> 1, + const_cast(mso_sptActionButtonBeginningEndCalc), SAL_N_ELEMENTS( mso_sptActionButtonBeginningEndCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static const mso_CustomShape msoActionButtonEnd = +{ + const_cast(mso_sptActionButtonEndVert), SAL_N_ELEMENTS( mso_sptActionButtonEndVert ), + const_cast(mso_sptActionButtonBeginningEndSegm), sizeof( mso_sptActionButtonBeginningEndSegm ) >> 1, + const_cast(mso_sptActionButtonBeginningEndCalc), SAL_N_ELEMENTS( mso_sptActionButtonBeginningEndCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 +}; +static 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 +}; +static 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 +}; +static const mso_CustomShape msoActionButtonReturn = +{ + const_cast(mso_sptActionButtonReturnVert), SAL_N_ELEMENTS( mso_sptActionButtonReturnVert ), + const_cast(mso_sptActionButtonReturnSegm), sizeof( mso_sptActionButtonReturnSegm ) >> 1, + const_cast(mso_sptActionButtonReturnCalc), SAL_N_ELEMENTS( mso_sptActionButtonReturnCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const mso_CustomShape msoActionButtonDocument = +{ + const_cast(mso_sptActionButtonDocumentVert), SAL_N_ELEMENTS( mso_sptActionButtonDocumentVert ), + const_cast(mso_sptActionButtonDocumentSegm), sizeof( mso_sptActionButtonDocumentSegm ) >> 1, + const_cast(mso_sptActionButtonDocumentCalc), SAL_N_ELEMENTS( mso_sptActionButtonDocumentCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const mso_CustomShape msoActionButtonSound = +{ + const_cast(mso_sptActionButtonSoundVert), SAL_N_ELEMENTS( mso_sptActionButtonSoundVert ), + const_cast(mso_sptActionButtonSoundSegm), sizeof( mso_sptActionButtonSoundSegm ) >> 1, + const_cast(mso_sptActionButtonSoundCalc), SAL_N_ELEMENTS( mso_sptActionButtonSoundCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const mso_CustomShape msoActionButtonMovie = +{ + const_cast(mso_sptActionButtonMovieVert), SAL_N_ELEMENTS( mso_sptActionButtonMovieVert ), + const_cast(mso_sptActionButtonMovieSegm), sizeof( mso_sptActionButtonMovieSegm ) >> 1, + const_cast(mso_sptActionButtonMovieCalc), SAL_N_ELEMENTS( mso_sptActionButtonMovieCalc ), + const_cast(mso_sptDefault1400), + const_cast(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ), + 21600, 21600, + 10800, 10800, + nullptr, 0, + const_cast(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptSmileyFaceSegm[] = +{ + 0xa203, 0x6000, 0x8000, + 0xa203, 0x6000, 0x8000, + 0xa203, 0x6000, 0x8000, + 0x4000, 0x2001, 0xaa00, 0x8000 +}; +static const SvxMSDffCalculationData mso_sptSmileyFaceCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 14510 } }, + { 0x8000, { 18520, 0, 0x400 } }, + { 0x4000, { 14510, 0x400, 0 } } +}; + +static const sal_Int32 mso_sptSmileyFaceDefault[] = +{ + 1, 18520 +}; +static const SvxMSDffHandle mso_sptSmileyHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 14510, 18520 } +}; +static const mso_CustomShape msoSmileyFace = +{ + const_cast(mso_sptSmileyFaceVert), SAL_N_ELEMENTS( mso_sptSmileyFaceVert ), + const_cast(mso_sptSmileyFaceSegm), sizeof( mso_sptSmileyFaceSegm ) >> 1, + const_cast(mso_sptSmileyFaceCalc), SAL_N_ELEMENTS( mso_sptSmileyFaceCalc ), + const_cast(mso_sptSmileyFaceDefault), + const_cast(mso_sptEllipseTextRect), SAL_N_ELEMENTS( mso_sptEllipseTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ), + const_cast(mso_sptSmileyHandle), SAL_N_ELEMENTS( mso_sptSmileyHandle ) // handles +}; + +static const SvxMSDffVertPair mso_sptDonutVert[] = // adj value 0 - 10800 +{ + { 10800, 10800 }, { 10800, 10800 }, { 0, 360 }, + { 10800, 10800 }, { 1 MSO_I, 1 MSO_I }, { 0, 360 } +}; +static const sal_uInt16 mso_sptDonutSegm[] = +{ + 0xa203, 0x6000, 0xa203, 0x8000 +}; +static const SvxMSDffCalculationData mso_sptDonutCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, + { 0x8000, { 10800, 0, DFF_Prop_adjustValue } } +}; +static const SvxMSDffHandle mso_sptDonutHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 10800, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoDonut = +{ + const_cast(mso_sptDonutVert), SAL_N_ELEMENTS( mso_sptDonutVert ), + const_cast(mso_sptDonutSegm), sizeof( mso_sptDonutSegm ) >> 1, + const_cast(mso_sptDonutCalc), SAL_N_ELEMENTS( mso_sptDonutCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptEllipseTextRect), SAL_N_ELEMENTS( mso_sptEllipseTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ), + const_cast(mso_sptDonutHandle), SAL_N_ELEMENTS( mso_sptDonutHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptNoSmokingSegm[] = +{ + 0xa203, 0x6000, 0xa404, 0x6000, 0xa404, 0x6000, 0x8000 +}; +static 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 +}; +static const SvxMSDffHandle mso_sptNoSmokingHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 10800, 10800, 10800, 0, 7200, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoNoSmoking = +{ + const_cast(mso_sptNoSmokingVert), SAL_N_ELEMENTS( mso_sptNoSmokingVert ), + const_cast(mso_sptNoSmokingSegm), sizeof( mso_sptNoSmokingSegm ) >> 1, + const_cast(mso_sptNoSmokingCalc), SAL_N_ELEMENTS( mso_sptNoSmokingCalc ), + const_cast(mso_sptDefault2700), + const_cast(mso_sptEllipseTextRect), SAL_N_ELEMENTS( mso_sptEllipseTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ), + const_cast(mso_sptNoSmokingHandle), SAL_N_ELEMENTS( mso_sptNoSmokingHandle ) // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptBlockArcSegm[] = +{ + 0xA404, 0xa504, 0x6001, 0x8000 +}; +static const sal_Int32 mso_sptBlockArcDefault[] = +{ + 2, 180, 5400 +}; +static 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 } } +}; +static const SvxMSDffHandle mso_sptBlockArcHandle[] = +{ + { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE, + 0x101, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoBlockArc = +{ + const_cast(mso_sptBlockArcVert), SAL_N_ELEMENTS( mso_sptBlockArcVert ), + const_cast(mso_sptBlockArcSegm), sizeof( mso_sptBlockArcSegm ) >> 1, + const_cast(mso_sptBlockArcCalc), SAL_N_ELEMENTS( mso_sptBlockArcCalc ), + const_cast(mso_sptBlockArcDefault), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptBlockArcHandle), SAL_N_ELEMENTS( mso_sptBlockArcHandle ) // handles +}; + +// aware : control points are always part of the bounding box +static 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 +}; +static const sal_uInt16 mso_sptHeartSegm[] = +{ + 0x4000, 0x0002, 0x2010, 0x0001, 0x2010, 0x0001, 0x6001, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptHeartTextRect[] = +{ + { { 5080, 2540 }, { 16520, 13550 } } +}; +static const SvxMSDffVertPair mso_sptHeartGluePoints[] = +{ + { 10800, 2180 }, { 3090, 10800 }, { 10800, 21600 }, { 18490, 10800 } +}; +static const mso_CustomShape msoHeart = +{ + const_cast(mso_sptHeartVert), SAL_N_ELEMENTS( mso_sptHeartVert ), + const_cast(mso_sptHeartSegm), sizeof( mso_sptHeartSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptHeartTextRect), SAL_N_ELEMENTS( mso_sptHeartTextRect ), + 21615, 21602, + MIN_INT32, MIN_INT32, + const_cast(mso_sptHeartGluePoints), SAL_N_ELEMENTS( mso_sptHeartGluePoints ), + nullptr, 0 // handles +}; + +static 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 } +}; +static const SvxMSDffTextRectangles mso_sptLightningBoldTextRect[] = +{ + { { 8680, 7410 }, { 13970, 14190 } } +}; +static const SvxMSDffVertPair mso_sptLightningBoldGluePoints[] = +{ + { 8458, 0 }, { 0, 3923 }, { 4993, 9720 }, { 9987, 14934 }, { 21600, 21600 }, + { 16558, 12016 }, { 12831, 6120 } +}; +static const mso_CustomShape msoLightningBold = +{ + const_cast(mso_sptLightningBoldVert), SAL_N_ELEMENTS( mso_sptLightningBoldVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptLightningBoldTextRect), SAL_N_ELEMENTS( mso_sptLightningBoldTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptLightningBoldGluePoints), SAL_N_ELEMENTS( mso_sptLightningBoldGluePoints ), + nullptr, 0 // handles +}; + +static 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 } +}; +static 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 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptSunTextRect[] = +{ + { { 0x34 MSO_I, 0x34 MSO_I }, { 0x35 MSO_I, 0x35 MSO_I } } +}; +static const SvxMSDffHandle mso_sptSunHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 10800, 10800, 10800, 2700, 10125, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoSun = +{ + const_cast(mso_sptSunVert), SAL_N_ELEMENTS( mso_sptSunVert ), + const_cast(mso_sptSunSegm), sizeof( mso_sptSunSegm ) >> 1, + const_cast(mso_sptSunCalc), SAL_N_ELEMENTS( mso_sptSunCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptSunTextRect), SAL_N_ELEMENTS( mso_sptSunTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + const_cast(mso_sptSunHandle), SAL_N_ELEMENTS( mso_sptSunHandle ) // handles +}; + +static 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 +}; +static const sal_uInt16 mso_sptMoonSegm[] = +{ + 0x4000, 0x2004, 0x6000, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptMoonTextRect[] = +{ + { { 9 MSO_I, 8 MSO_I }, { 0 MSO_I, 0xa MSO_I } } +}; +static const SvxMSDffVertPair mso_sptMoonGluePoints[] = +{ + { 21600, 0 }, { 0, 10800 }, { 21600, 21600 }, { 0 MSO_I, 10800 } +}; +static const SvxMSDffHandle mso_sptMoonHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 10800, 10800, 10800, 0, 18900, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoMoon = +{ + const_cast(mso_sptMoonVert), SAL_N_ELEMENTS( mso_sptMoonVert ), + const_cast(mso_sptMoonSegm), sizeof( mso_sptMoonSegm ) >> 1, + const_cast(mso_sptMoonCalc), SAL_N_ELEMENTS( mso_sptMoonCalc ), + const_cast(mso_sptDefault10800), + const_cast(mso_sptMoonTextRect), SAL_N_ELEMENTS( mso_sptMoonTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptMoonGluePoints), SAL_N_ELEMENTS( mso_sptMoonGluePoints ), + const_cast(mso_sptMoonHandle), SAL_N_ELEMENTS( mso_sptMoonHandle ) // handles +}; + +static 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 } +}; +static 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 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptBracketPairTextRect[] = +{ + { { 8 MSO_I, 9 MSO_I }, { 0xa MSO_I, 0xb MSO_I } } +}; +static const SvxMSDffHandle mso_sptBracketPairHandle[] = +{ + { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED, + 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoBracketPair = +{ + const_cast(mso_sptBracketPairVert), SAL_N_ELEMENTS( mso_sptBracketPairVert ), + const_cast(mso_sptBracketPairSegm), sizeof( mso_sptBracketPairSegm ) >> 1, + const_cast(mso_sptBracketPairCalc), SAL_N_ELEMENTS( mso_sptBracketPairCalc ), + const_cast(mso_sptDefault3700), + const_cast(mso_sptBracketPairTextRect), SAL_N_ELEMENTS( mso_sptBracketPairTextRect ), + 21600, 21600, + 10800, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + const_cast(mso_sptBracketPairHandle), SAL_N_ELEMENTS( mso_sptBracketPairHandle ) // handles +}; + +static const sal_uInt16 mso_sptPlaqueSegm[] = +{ + 0x4000, 0xa801, 0x0001, 0xa701, 0x0001, 0xa801, 0x0001, 0xa701, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptPlaqueTextRect[] = +{ + { { 0xc MSO_I, 0xd MSO_I }, { 0xe MSO_I, 0xf MSO_I } } +}; +static const SvxMSDffHandle mso_sptPlaqueHandle[] = +{ + { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED, + 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoPlaque = +{ + const_cast(mso_sptBracketPairVert), SAL_N_ELEMENTS( mso_sptBracketPairVert ), + const_cast(mso_sptPlaqueSegm), sizeof( mso_sptPlaqueSegm ) >> 1, + const_cast(mso_sptBracketPairCalc), SAL_N_ELEMENTS( mso_sptBracketPairCalc ), + const_cast(mso_sptDefault3600), + const_cast(mso_sptPlaqueTextRect), SAL_N_ELEMENTS( mso_sptPlaqueTextRect ), + 21600, 21600, + 10800, 10800, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + const_cast(mso_sptPlaqueHandle), SAL_N_ELEMENTS( mso_sptPlaqueHandle ) // handles +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const SvxMSDffTextRectangles mso_sptBracePairTextRect[] = +{ + { { 0xb MSO_I, 0xc MSO_I }, { 0xd MSO_I, 0xe MSO_I } } +}; +static const SvxMSDffHandle mso_sptBracePairHandle[] = +{ + { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 5400 } +}; +static const mso_CustomShape msoBracePair = +{ + const_cast(mso_sptBracePairVert), SAL_N_ELEMENTS( mso_sptBracePairVert ), + const_cast(mso_sptBracePairSegm), sizeof( mso_sptBracePairSegm ) >> 1, + const_cast(mso_sptBracePairCalc), SAL_N_ELEMENTS( mso_sptBracePairCalc ), + const_cast(mso_sptDefault1800), + const_cast(mso_sptBracePairTextRect), SAL_N_ELEMENTS( mso_sptBracePairTextRect ), + 21600, 21600, + 10800, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + const_cast(mso_sptBracePairHandle), SAL_N_ELEMENTS( mso_sptBracePairHandle ) // handles +}; + +static 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 } } +}; +static const sal_uInt16 mso_sptBracketSegm[] = +{ + 0x4000, 0x2001, 0x0001, 0x2001, 0x8000 +}; +static 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 } +}; +static const SvxMSDffTextRectangles mso_sptLeftBracketTextRect[] = +{ + { { 6350, 3 MSO_I }, { 21600, 4 MSO_I } } +}; +static const SvxMSDffVertPair mso_sptLeftBracketGluePoints[] = +{ + { 21600, 0 }, { 0, 10800 }, { 21600, 21600 } +}; +static const SvxMSDffHandle mso_sptLeftBracketHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 } +}; +static const mso_CustomShape msoLeftBracket = +{ + const_cast(mso_sptLeftBracketVert), SAL_N_ELEMENTS( mso_sptLeftBracketVert ), + const_cast(mso_sptBracketSegm), sizeof( mso_sptBracketSegm ) >> 1, + const_cast(mso_sptBracketCalc), SAL_N_ELEMENTS( mso_sptBracketCalc ), + const_cast(mso_sptDefault1800), + const_cast(mso_sptLeftBracketTextRect), SAL_N_ELEMENTS( mso_sptLeftBracketTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptLeftBracketGluePoints), SAL_N_ELEMENTS( mso_sptLeftBracketGluePoints ), + const_cast(mso_sptLeftBracketHandle), SAL_N_ELEMENTS( mso_sptLeftBracketHandle ) // handles +}; +static 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 } +}; +static const SvxMSDffTextRectangles mso_sptRightBracketTextRect[] = +{ + { { 0, 3 MSO_I }, { 15150, 4 MSO_I } } +}; +static const SvxMSDffVertPair mso_sptRightBracketGluePoints[] = +{ + { 0, 0 }, { 0, 21600 }, { 21600, 10800 } +}; +static const SvxMSDffHandle mso_sptRightBracketHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 1, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 } +}; +static const mso_CustomShape msoRightBracket = +{ + const_cast(mso_sptRightBracketVert), SAL_N_ELEMENTS( mso_sptRightBracketVert ), + const_cast(mso_sptBracketSegm), sizeof( mso_sptBracketSegm ) >> 1, + const_cast(mso_sptBracketCalc), SAL_N_ELEMENTS( mso_sptBracketCalc ), + const_cast(mso_sptDefault1800), + const_cast(mso_sptRightBracketTextRect), SAL_N_ELEMENTS( mso_sptRightBracketTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptRightBracketGluePoints), SAL_N_ELEMENTS( mso_sptRightBracketGluePoints ), + const_cast(mso_sptRightBracketHandle), SAL_N_ELEMENTS( mso_sptRightBracketHandle ) // handles +}; + +static 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 } } +}; +static const sal_uInt16 mso_sptBraceSegm[] = +{ + 0x4000, 0x2001, 0x0001, 0x2002, 0x0001, 0x2001, 0x8000 +}; +static const sal_Int32 mso_sptBraceDefault[] = +{ + 2, 1800, 10800 +}; +static 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 +}; +static const SvxMSDffTextRectangles mso_sptLeftBraceTextRect[] = +{ + { { 13800, 9 MSO_I }, { 21600, 10 MSO_I } } +}; +static 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 } +}; +static const mso_CustomShape msoLeftBrace = // adj value0 0 -> 5400 +{ // adj value1 0 -> 21600 + const_cast(mso_sptLeftBraceVert), SAL_N_ELEMENTS( mso_sptLeftBraceVert ), + const_cast(mso_sptBraceSegm), sizeof( mso_sptBraceSegm ) >> 1, + const_cast(mso_sptBraceCalc), SAL_N_ELEMENTS( mso_sptBraceCalc ), + const_cast(mso_sptBraceDefault), + const_cast(mso_sptLeftBraceTextRect), SAL_N_ELEMENTS( mso_sptLeftBraceTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptLeftBracketGluePoints), SAL_N_ELEMENTS( mso_sptLeftBracketGluePoints ), + const_cast(mso_sptLeftBraceHandle), SAL_N_ELEMENTS( mso_sptLeftBraceHandle ) // handles +}; +static 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 +}; +static const SvxMSDffTextRectangles mso_sptRightBraceTextRect[] = +{ + { { 0, 9 MSO_I }, { 7800, 10 MSO_I } } +}; +static 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 } +}; +static const mso_CustomShape msoRightBrace = // adj value0 0 -> 5400 +{ // adj value1 0 -> 21600 + const_cast(mso_sptRightBraceVert), SAL_N_ELEMENTS( mso_sptRightBraceVert ), + const_cast(mso_sptBraceSegm), sizeof( mso_sptBraceSegm ) >> 1, + const_cast(mso_sptBraceCalc), SAL_N_ELEMENTS( mso_sptBraceCalc ), + const_cast(mso_sptBraceDefault), + const_cast(mso_sptRightBraceTextRect), SAL_N_ELEMENTS( mso_sptRightBraceTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptRightBracketGluePoints), SAL_N_ELEMENTS( mso_sptRightBracketGluePoints ), + const_cast(mso_sptRightBraceHandle), SAL_N_ELEMENTS( mso_sptRightBraceHandle ) // handles +}; + +static 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 } +}; +static const SvxMSDffTextRectangles mso_sptIrregularSeal1TextRect[] = +{ + { { 4680, 6570 }, { 16140, 13280 } } +}; +static const SvxMSDffVertPair mso_sptIrregularSeal1GluePoints[] = +{ + { 14623, 106 }, { 106, 8718 }, { 8590, 21600 }, { 21600, 13393 } +}; +static const mso_CustomShape msoIrregularSeal1 = +{ + const_cast(mso_sptIrregularSeal1Vert), SAL_N_ELEMENTS( mso_sptIrregularSeal1Vert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptIrregularSeal1TextRect), SAL_N_ELEMENTS( mso_sptIrregularSeal1TextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptIrregularSeal1GluePoints), SAL_N_ELEMENTS( mso_sptIrregularSeal1GluePoints ), + nullptr, 0 // handles +}; + +static 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 } +}; +static const SvxMSDffTextRectangles mso_sptIrregularSeal2TextRect[] = +{ + { { 5400, 6570 }, { 14160, 15290 } } +}; +static const SvxMSDffVertPair mso_sptIrregularSeal2GluePoints[] = +{ + { 9722, 1887 }, { 0, 12875 }, { 11614, 18844 }, { 21600, 6646 } +}; +static const mso_CustomShape msoIrregularSeal2 = +{ + const_cast(mso_sptIrregularSeal2Vert), SAL_N_ELEMENTS( mso_sptIrregularSeal2Vert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptIrregularSeal2TextRect), SAL_N_ELEMENTS( mso_sptIrregularSeal2TextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptIrregularSeal2GluePoints), SAL_N_ELEMENTS( mso_sptIrregularSeal2GluePoints ), + nullptr, 0 // handles +}; + +static 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 } +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptSeal4TextRect[] = +{ + { { 4 MSO_I, 4 MSO_I }, { 3 MSO_I, 3 MSO_I } } +}; +static const SvxMSDffHandle mso_sptSealHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 10800, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoSeal4 = +{ + const_cast(mso_sptSeal4Vert), SAL_N_ELEMENTS( mso_sptSeal4Vert ), + nullptr, 0, + const_cast(mso_sptSeal4Calc), SAL_N_ELEMENTS( mso_sptSeal4Calc ), + const_cast(mso_sptDefault8100), + const_cast(mso_sptSeal4TextRect), SAL_N_ELEMENTS( mso_sptSeal4TextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) // handles +}; + +static 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 } +}; +static const SvxMSDffTextRectangles mso_sptStarTextRect[] = +{ + { { 6722, 8256 }, { 14878, 15460 } } +}; +static const mso_CustomShape msoStar = +{ + const_cast(mso_sptStarVert), SAL_N_ELEMENTS( mso_sptStarVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptStarTextRect), SAL_N_ELEMENTS( mso_sptStarTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + nullptr, 0 // handles +}; + +static 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 } } +}; +static 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 } +}; +static const SvxMSDffTextRectangles mso_sptSealTextRect[] = +{ + { { 1 MSO_I, 2 MSO_I }, { 3 MSO_I, 4 MSO_I } } +}; +static const mso_CustomShape msoSeal8 = +{ + const_cast(mso_sptSeal8Vert), SAL_N_ELEMENTS( mso_sptSeal8Vert ), + nullptr, 0, + const_cast(mso_sptSeal24Calc), SAL_N_ELEMENTS( mso_sptSeal24Calc ), + const_cast(mso_sptDefault2500), + const_cast(mso_sptSealTextRect), SAL_N_ELEMENTS( mso_sptSealTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) // handles +}; +static 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 } +}; +static 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 } } +}; +static const mso_CustomShape msoSeal16 = +{ + const_cast(mso_sptSeal16Vert), SAL_N_ELEMENTS( mso_sptSeal16Vert ), + nullptr, 0, + const_cast(mso_sptSeal16Calc), SAL_N_ELEMENTS( mso_sptSeal16Calc ), + const_cast(mso_sptDefault2500), + const_cast(mso_sptSealTextRect), SAL_N_ELEMENTS( mso_sptSealTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) // handles +}; +static 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 } +}; +static const mso_CustomShape msoSeal24 = +{ + const_cast(mso_sptSeal24Vert), SAL_N_ELEMENTS( mso_sptSeal24Vert ), + nullptr, 0, + const_cast(mso_sptSeal24Calc), SAL_N_ELEMENTS( mso_sptSeal24Calc ), + const_cast(mso_sptDefault2500), + const_cast(mso_sptSealTextRect), SAL_N_ELEMENTS( mso_sptSealTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) // handles +}; +static 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 } } +}; +static 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 } +}; +static const mso_CustomShape msoSeal32 = +{ + const_cast(mso_sptSeal32Vert), SAL_N_ELEMENTS( mso_sptSeal32Vert ), + nullptr, 0, + const_cast(mso_sptSeal32Calc), SAL_N_ELEMENTS( mso_sptSeal32Calc ), + const_cast(mso_sptDefault2500), + const_cast(mso_sptSealTextRect), SAL_N_ELEMENTS( mso_sptSealTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) +}; + +static 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 +}; +static 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 +}; +static 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 +}; +static const sal_Int32 mso_sptRibbon2Default[] = +{ + 2, 5400, 18900 +}; +static const SvxMSDffTextRectangles mso_sptRibbon2TextRect[] = +{ + { { 0 MSO_I, 0 }, { 19 MSO_I, 1 MSO_I } } +}; +static 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 } +}; +static const mso_CustomShape msoRibbon2 = +{ + const_cast(mso_sptRibbon2Vert), SAL_N_ELEMENTS( mso_sptRibbon2Vert ), + const_cast(mso_sptRibbon2Segm), sizeof( mso_sptRibbon2Segm ) >> 1, + const_cast(mso_sptRibbon2Calc), SAL_N_ELEMENTS( mso_sptRibbon2Calc ), + const_cast(mso_sptRibbon2Default), + const_cast(mso_sptRibbon2TextRect), SAL_N_ELEMENTS( mso_sptRibbon2TextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptRibbon2Handle), SAL_N_ELEMENTS( mso_sptRibbon2Handle ) +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const sal_Int32 mso_sptRibbonDefault[] = +{ + 2, 5400, 2700 +}; +static const SvxMSDffTextRectangles mso_sptRibbonTextRect[] = +{ + { { 0 MSO_I, 10 MSO_I }, { 9 MSO_I, 21600 } } +}; +static const SvxMSDffVertPair mso_sptRibbonGluePoints[] = +{ + { 17 MSO_I, 10 MSO_I }, { 2700, 14 MSO_I }, { 17 MSO_I, 21600 }, { 18 MSO_I, 14 MSO_I } +}; +static 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 } +}; +static const mso_CustomShape msoRibbon = +{ + const_cast(mso_sptRibbonVert), SAL_N_ELEMENTS( mso_sptRibbonVert ), + const_cast(mso_sptRibbonSegm), sizeof( mso_sptRibbonSegm ) >> 1, + const_cast(mso_sptRibbonCalc), SAL_N_ELEMENTS( mso_sptRibbonCalc ), + const_cast(mso_sptRibbonDefault), + const_cast(mso_sptRibbonTextRect), SAL_N_ELEMENTS( mso_sptRibbonTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptRibbonGluePoints), SAL_N_ELEMENTS( mso_sptRibbonGluePoints ), + const_cast(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 +static 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 } +}; + +static 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*/ +}; + +static 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 +}; + +static const SvxMSDffTextRectangles mso_sptEllipseRibbonTextRect[] = +{//@0,@1,@22,@25 + { { 0 MSO_I, 1 MSO_I }, { 22 MSO_I, 25 MSO_I } } +}; + +static const sal_Int32 mso_sptEllipseRibbonDefault[] = +{ + 3,5400,5400,18900 +}; + +static 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*/ } +}; + +static const mso_CustomShape msosptEllipseRibbon = +{ + const_cast(mso_sptEllipseRibbonVert), SAL_N_ELEMENTS( mso_sptEllipseRibbonVert ), + const_cast(mso_sptEllipseRibbonSegm), sizeof( mso_sptEllipseRibbonSegm ) >> 1, + const_cast(mso_sptEllipseRibbonCalc), SAL_N_ELEMENTS( mso_sptEllipseRibbonCalc ), + const_cast(mso_sptEllipseRibbonDefault), + const_cast(mso_sptEllipseRibbonTextRect), SAL_N_ELEMENTS( mso_sptEllipseRibbonTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(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 +static 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 } +}; +static 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*/ +}; + +static 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 +}; + +static const SvxMSDffTextRectangles mso_sptEllipseRibbon2TextRect[] = +{//@0,@22,@19,@1 + { { 0 MSO_I, 22 MSO_I }, { 19 MSO_I, 1 MSO_I } } +}; + +static const sal_Int32 mso_sptEllipseRibbon2Default[] = +{ + 3,5400,16200,2700 +}; + +static 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*/ } +}; + +static const mso_CustomShape msosptEllipseRibbon2 = +{ + const_cast(mso_sptEllipseRibbon2Vert), SAL_N_ELEMENTS( mso_sptEllipseRibbon2Vert ), + const_cast(mso_sptEllipseRibbon2Segm), sizeof( mso_sptEllipseRibbon2Segm ) >> 1, + const_cast(mso_sptEllipseRibbon2Calc), SAL_N_ELEMENTS( mso_sptEllipseRibbon2Calc ), + const_cast(mso_sptEllipseRibbon2Default), + const_cast(mso_sptEllipseRibbon2TextRect), SAL_N_ELEMENTS( mso_sptEllipseRibbon2TextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptEllipseRibbon2Handle), SAL_N_ELEMENTS( mso_sptEllipseRibbon2Handle ) +}; +// End +static 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 } +}; +static 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 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptScrollTextRect[] = +{ + { { 0 MSO_I, 0 MSO_I }, { 3 MSO_I, 12 MSO_I } } +}; +static const SvxMSDffHandle mso_sptVerticalScrollHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 5400 } +}; +static const mso_CustomShape msoVerticalScroll = +{ + const_cast(mso_sptVerticalScrollVert), SAL_N_ELEMENTS( mso_sptVerticalScrollVert ), + const_cast(mso_sptVerticalScrollSegm), sizeof( mso_sptVerticalScrollSegm ) >> 1, + const_cast(mso_sptScrollCalc), SAL_N_ELEMENTS( mso_sptScrollCalc ), + const_cast(mso_sptDefault2700), + const_cast(mso_sptScrollTextRect), SAL_N_ELEMENTS( mso_sptScrollTextRect ), + 21600, 21600, + 11000, 10800, + nullptr, 0, + const_cast(mso_sptVerticalScrollHandle), SAL_N_ELEMENTS( mso_sptVerticalScrollHandle ) +}; +static 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 } +}; +static 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 +}; +static const SvxMSDffHandle mso_sptHorizontalScrollHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0, 10800, 10800, 0, 5400, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoHorizontalScroll = +{ + const_cast(mso_sptHorizontalScrollVert), SAL_N_ELEMENTS( mso_sptHorizontalScrollVert ), + const_cast(mso_sptHorizontalScrollSegm), sizeof( mso_sptHorizontalScrollSegm ) >> 1, + const_cast(mso_sptScrollCalc), SAL_N_ELEMENTS( mso_sptScrollCalc ), + const_cast(mso_sptDefault2700), + const_cast(mso_sptScrollTextRect), SAL_N_ELEMENTS( mso_sptScrollTextRect ), + 21600, 21600, + 10800, 11000, + nullptr, 0, + const_cast(mso_sptHorizontalScrollHandle), SAL_N_ELEMENTS( mso_sptHorizontalScrollHandle ) +}; + +static const SvxMSDffVertPair mso_sptFlowChartProcessVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 } +}; +static const mso_CustomShape msoFlowChartProcess = +{ + const_cast(mso_sptFlowChartProcessVert), SAL_N_ELEMENTS( mso_sptFlowChartProcessVert ), + nullptr, 0, + nullptr, 0, + nullptr, + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptFlowChartAlternateProcessSegm[] = +{ + 0x4000, 0xa801, 0x0001, 0xa701, 0x0001, 0xa801, 0x0001, 0xa701, 0x6000, 0x8000 +}; +static 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 } } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartAlternateProcessTextRect[] = +{ + { { 4 MSO_I, 6 MSO_I }, { 5 MSO_I, 7 MSO_I } } +}; +static const mso_CustomShape msoFlowChartAlternateProcess = +{ + const_cast(mso_sptFlowChartAlternateProcessVert), SAL_N_ELEMENTS( mso_sptFlowChartAlternateProcessVert ), + const_cast(mso_sptFlowChartAlternateProcessSegm), sizeof( mso_sptFlowChartAlternateProcessSegm ) >> 1, + const_cast(mso_sptFlowChartAlternateProcessCalc), SAL_N_ELEMENTS( mso_sptFlowChartAlternateProcessCalc ), + nullptr, + const_cast(mso_sptFlowChartAlternateProcessTextRect), SAL_N_ELEMENTS( mso_sptFlowChartAlternateProcessTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartDecisionVert[] = +{ + { 0, 10800 }, { 10800, 0 }, { 21600, 10800 }, { 10800, 21600 }, { 0, 10800 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartDecisionTextRect[] = +{ + { { 5400, 5400 }, { 16200, 16200 } } +}; +static const mso_CustomShape msoFlowChartDecision = +{ + const_cast(mso_sptFlowChartDecisionVert), SAL_N_ELEMENTS( mso_sptFlowChartDecisionVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartDecisionTextRect), SAL_N_ELEMENTS( mso_sptFlowChartDecisionTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartInputOutputVert[] = +{ + { 4230, 0 }, { 21600, 0 }, { 17370, 21600 }, { 0, 21600 }, { 4230, 0 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartInputOutputTextRect[] = +{ + { { 4230, 0 }, { 17370, 21600 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartInputOutputGluePoints[] = +{ + { 12960, 0 }, { 10800, 0 }, { 2160, 10800 }, { 8600, 21600 }, { 10800, 21600 }, { 19400, 10800 } +}; +static const mso_CustomShape msoFlowChartInputOutput = +{ + const_cast(mso_sptFlowChartInputOutputVert), SAL_N_ELEMENTS( mso_sptFlowChartInputOutputVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartInputOutputTextRect), SAL_N_ELEMENTS( mso_sptFlowChartInputOutputTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartInputOutputGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartInputOutputGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartPredefinedProcessVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, + + { 2540, 0 }, { 2540, 21600 }, + + { 21600 - 2540, 0 }, { 21600 - 2540, 21600 } +}; +static const sal_uInt16 mso_sptFlowChartPredefinedProcessSegm[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartPredefinedProcessTextRect[] = +{ + { { 2540, 0 }, { 21600 - 2540, 21600 } } +}; +static const mso_CustomShape msoFlowChartPredefinedProcess = +{ + const_cast(mso_sptFlowChartPredefinedProcessVert), SAL_N_ELEMENTS( mso_sptFlowChartPredefinedProcessVert ), + const_cast(mso_sptFlowChartPredefinedProcessSegm), sizeof( mso_sptFlowChartPredefinedProcessSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartPredefinedProcessTextRect), SAL_N_ELEMENTS( mso_sptFlowChartPredefinedProcessTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartInternalStorageVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, + + { 4230, 0 }, { 4230, 21600 }, + + { 0, 4230 }, { 21600, 4230 } +}; +static const sal_uInt16 mso_sptFlowChartInternalStorageSegm[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartInternalStorageTextRect[] = +{ + { { 4230, 4230 }, { 21600, 21600 } } +}; +static const mso_CustomShape msoFlowChartInternalStorage = +{ + const_cast(mso_sptFlowChartInternalStorageVert), SAL_N_ELEMENTS( mso_sptFlowChartInternalStorageVert ), + const_cast(mso_sptFlowChartInternalStorageSegm), sizeof( mso_sptFlowChartInternalStorageSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartInternalStorageTextRect), SAL_N_ELEMENTS( mso_sptFlowChartInternalStorageTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartDocumentVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 17360 }, + { 13050, 17220 }, { 13340, 20770 }, { 5620, 21600 }, // ccp + { 2860, 21100 }, { 1850, 20700 }, { 0, 20120 } // ccp +}; +static const sal_uInt16 mso_sptFlowChartDocumentSegm[] = +{ + 0x4000, 0x0002, 0x2002, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartDocumentTextRect[] = +{ + { { 0, 0 }, { 21600, 17360 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartDocumentGluePoints[] = +{ + { 10800, 0 }, { 0, 10800 }, { 10800, 20320 }, { 21600, 10800 } +}; +static const mso_CustomShape msoFlowChartDocument = +{ + const_cast(mso_sptFlowChartDocumentVert), SAL_N_ELEMENTS( mso_sptFlowChartDocumentVert ), + const_cast(mso_sptFlowChartDocumentSegm), sizeof( mso_sptFlowChartDocumentSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartDocumentTextRect), SAL_N_ELEMENTS( mso_sptFlowChartDocumentTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartDocumentGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartDocumentGluePoints ), + nullptr, 0 // handles +}; + +static 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 } +}; +static const sal_uInt16 mso_sptFlowChartMultidocumentSegm[] = +{ + 0x4000, 0x000a, 0x2002, 0x6000, 0x8000, + 0x4000, 0xaa00, 0x0002, 0x8000, // NO FILL + 0x4000, 0xaa00, 0x0002, 0x8000 // NO FILL +}; +static const SvxMSDffTextRectangles mso_sptFlowChartMultidocumentTextRect[] = +{ + { { 0, 3600 }, { 21600 - 3000, 14409 + 3600 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartMultidocumentGluePoints[] = +{ + { 10800, 0 }, { 0, 10800 }, { 10800, 19890 }, { 21600, 10800 } +}; +static const mso_CustomShape msoFlowChartMultidocument = +{ + const_cast(mso_sptFlowChartMultidocumentVert), SAL_N_ELEMENTS( mso_sptFlowChartMultidocumentVert ), + const_cast(mso_sptFlowChartMultidocumentSegm), sizeof( mso_sptFlowChartMultidocumentSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartMultidocumentTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMultidocumentTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartMultidocumentGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartMultidocumentGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartTerminatorVert[] = +{ + { 3470, 21600 }, { 0, 10800 }, { 3470, 0 }, { 18130, 0 }, + { 21600, 10800 }, { 18130, 21600 } +}; +static const sal_uInt16 mso_sptFlowChartTerminatorSegm[] = +{ + 0x4000, 0xa702, 0x0001, 0xa702, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartTerminatorTextRect[] = +{ + { { 1060, 3180 }, { 20540, 18420 } } +}; +static const mso_CustomShape msoFlowChartTerminator = +{ + const_cast(mso_sptFlowChartTerminatorVert), SAL_N_ELEMENTS( mso_sptFlowChartTerminatorVert ), + const_cast(mso_sptFlowChartTerminatorSegm), sizeof( mso_sptFlowChartTerminatorSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartTerminatorTextRect), SAL_N_ELEMENTS( mso_sptFlowChartTerminatorTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartPreparationVert[] = +{ + { 4350, 0 }, { 17250, 0 }, { 21600, 10800 }, { 17250, 21600 }, + { 4350, 21600 }, { 0, 10800 }, { 4350, 0 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartPreparationTextRect[] = +{ + { { 4350, 0 }, { 17250, 21600 } } +}; +static const mso_CustomShape msoFlowChartPreparation = +{ + const_cast(mso_sptFlowChartPreparationVert), SAL_N_ELEMENTS( mso_sptFlowChartPreparationVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartPreparationTextRect), SAL_N_ELEMENTS( mso_sptFlowChartPreparationTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartManualInputVert[] = +{ + { 0, 4300 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 4300 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartManualInputTextRect[] = +{ + { { 0, 4300 }, { 21600, 21600 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartManualInputGluePoints[] = +{ + { 10800, 2150 }, { 0, 10800 }, { 10800, 19890 }, { 21600, 10800 } +}; +static const mso_CustomShape msoFlowChartManualInput = +{ + const_cast(mso_sptFlowChartManualInputVert), SAL_N_ELEMENTS( mso_sptFlowChartManualInputVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartManualInputTextRect), SAL_N_ELEMENTS( mso_sptFlowChartManualInputTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartManualInputGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartManualInputGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartManualOperationVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 17250, 21600 }, { 4350, 21600 }, { 0, 0 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartManualOperationTextRect[] = +{ + { { 4350, 0 }, { 17250, 21600 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartManualOperationGluePoints[] = +{ + { 10800, 0 }, { 2160, 10800 }, { 10800, 21600 }, { 19440, 10800 } +}; +static const mso_CustomShape msoFlowChartManualOperation = +{ + const_cast(mso_sptFlowChartManualOperationVert), SAL_N_ELEMENTS( mso_sptFlowChartManualOperationVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartManualOperationTextRect), SAL_N_ELEMENTS( mso_sptFlowChartManualOperationTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartManualOperationGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartManualOperationGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartConnectorVert[] = +{ + { 10800, 10800 }, { 10800, 10800 }, { 0, 360 } +}; +static const sal_uInt16 mso_sptFlowChartConnectorSegm[] = +{ + 0xa203, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartConnectorTextRect[] = +{ + { { 3180, 3180 }, { 18420, 18420 } } +}; +static const mso_CustomShape msoFlowChartConnector = +{ + const_cast(mso_sptFlowChartConnectorVert), SAL_N_ELEMENTS( mso_sptFlowChartConnectorVert ), + const_cast(mso_sptFlowChartConnectorSegm), sizeof( mso_sptFlowChartConnectorSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartConnectorTextRect), SAL_N_ELEMENTS( mso_sptFlowChartConnectorTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartOffpageConnectorVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 17150 }, { 10800, 21600 }, + { 0, 17150 }, { 0, 0 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartOffpageConnectorTextRect[] = +{ + { { 0, 0 }, { 21600, 17150 } } +}; +static const mso_CustomShape msoFlowChartOffpageConnector = +{ + const_cast(mso_sptFlowChartOffpageConnectorVert), SAL_N_ELEMENTS( mso_sptFlowChartOffpageConnectorVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartOffpageConnectorTextRect), SAL_N_ELEMENTS( mso_sptFlowChartOffpageConnectorTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartPunchedCardVert[] = +{ + { 4300, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, + { 0, 4300 }, { 4300, 0 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartPunchedCardTextRect[] = +{ + { { 0, 4300 }, { 21600, 21600 } } +}; +static const mso_CustomShape msoFlowChartPunchedCard = +{ + const_cast(mso_sptFlowChartPunchedCardVert), SAL_N_ELEMENTS( mso_sptFlowChartPunchedCardVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartPunchedCardTextRect), SAL_N_ELEMENTS( mso_sptFlowChartPunchedCardTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static 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 +}; +static const sal_uInt16 mso_sptFlowChartPunchedTapeSegm[] = +{ + 0x4000, 0x2004, 0x0001, 0x2004, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartPunchedTapeTextRect[] = +{ + { { 0, 4360 }, { 21600, 17240 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartPunchedTapeGluePoints[] = +{ + { 10800, 2020 }, { 0, 10800 }, { 10800, 19320 }, { 21600, 10800 } +}; +static const mso_CustomShape msoFlowChartPunchedTape = +{ + const_cast(mso_sptFlowChartPunchedTapeVert), SAL_N_ELEMENTS( mso_sptFlowChartPunchedTapeVert ), + const_cast(mso_sptFlowChartPunchedTapeSegm), sizeof( mso_sptFlowChartPunchedTapeSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartPunchedTapeTextRect), SAL_N_ELEMENTS( mso_sptFlowChartPunchedTapeTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartPunchedTapeGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartPunchedTapeGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartSummingJunctionVert[] = +{ + { 10800, 10800 }, { 10800, 10800 }, { 0, 360 }, + + { 3100, 3100 }, + { 18500, 18500 }, + + { 3100, 18500 }, + { 18500, 3100 } +}; +static const sal_uInt16 mso_sptFlowChartSummingJunctionSegm[] = +{ + 0xa203, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartSummingJunctionTextRect[] = +{ + { { 3100, 3100 }, { 18500, 18500 } } +}; +static const mso_CustomShape msoFlowChartSummingJunction = +{ + const_cast(mso_sptFlowChartSummingJunctionVert), SAL_N_ELEMENTS( mso_sptFlowChartSummingJunctionVert ), + const_cast(mso_sptFlowChartSummingJunctionSegm), sizeof( mso_sptFlowChartSummingJunctionSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartSummingJunctionTextRect), SAL_N_ELEMENTS( mso_sptFlowChartSummingJunctionTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartOrVert[] = +{ + { 10800, 10800 }, { 10800, 10800 }, { 0, 360 }, + + { 0, 10800 }, { 21600, 10800 }, + + { 10800, 0 }, { 10800, 21600 } +}; +static const sal_uInt16 mso_sptFlowChartOrSegm[] = +{ + 0xa203, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartOrTextRect[] = +{ + { { 3100, 3100 }, { 18500, 18500 } } +}; +static const mso_CustomShape msoFlowChartOr = +{ + const_cast(mso_sptFlowChartOrVert), SAL_N_ELEMENTS( mso_sptFlowChartOrVert ), + const_cast(mso_sptFlowChartOrSegm), sizeof( mso_sptFlowChartOrSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartOrTextRect), SAL_N_ELEMENTS( mso_sptFlowChartOrTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartCollateVert[] = +{ + { 0, 0 }, { 21600, 21600 }, { 0, 21600 }, { 21600, 0 }, { 0, 0 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartCollateTextRect[] = +{ + { { 5400, 5400 }, { 16200, 16200 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartCollateGluePoints[] = +{ + { 10800, 0 }, { 10800, 10800 }, { 10800, 21600 } +}; +static const mso_CustomShape msoFlowChartCollate = +{ + const_cast(mso_sptFlowChartCollateVert), SAL_N_ELEMENTS( mso_sptFlowChartCollateVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartCollateTextRect), SAL_N_ELEMENTS( mso_sptFlowChartCollateTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartCollateGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartCollateGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartSortVert[] = +{ + { 0, 10800 }, { 10800, 0 }, { 21600, 10800 }, { 10800, 21600 }, + + { 0, 10800 }, { 21600, 10800 } +}; +static const sal_uInt16 mso_sptFlowChartSortSegm[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartSortTextRect[] = +{ + { { 5400, 5400 }, { 16200, 16200 } } +}; +static const mso_CustomShape msoFlowChartSort = +{ + const_cast(mso_sptFlowChartSortVert), SAL_N_ELEMENTS( mso_sptFlowChartSortVert ), + const_cast(mso_sptFlowChartSortSegm), sizeof( mso_sptFlowChartSortSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartSortTextRect), SAL_N_ELEMENTS( mso_sptFlowChartSortTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartExtractVert[] = +{ + { 10800, 0 }, { 21600, 21600 }, { 0, 21600 }, { 10800, 0 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartExtractTextRect[] = +{ + { { 5400, 10800 }, { 16200, 21600 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartExtractGluePoints[] = +{ + { 10800, 0 }, { 5400, 10800 }, { 10800, 21600 }, { 16200, 10800 } +}; +static const mso_CustomShape msoFlowChartExtract = +{ + const_cast(mso_sptFlowChartExtractVert), SAL_N_ELEMENTS( mso_sptFlowChartExtractVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartExtractTextRect), SAL_N_ELEMENTS( mso_sptFlowChartExtractTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartExtractGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartExtractGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartMergeVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 10800, 21600 }, { 0, 0 } +}; +static const SvxMSDffTextRectangles mso_sptFlowChartMergeTextRect[] = +{ + { { 5400, 0 }, { 16200, 10800 } } +}; +static const mso_CustomShape msoFlowChartMerge = +{ + const_cast(mso_sptFlowChartMergeVert), SAL_N_ELEMENTS( mso_sptFlowChartMergeVert ), + nullptr, 0, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartMergeTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMergeTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartExtractGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartExtractGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartOnlineStorageVert[] = +{ + { 3600, 21600 }, { 0, 10800 }, { 3600, 0 }, { 21600, 0 }, + { 18000, 10800 }, { 21600, 21600 } +}; +static const sal_uInt16 mso_sptFlowChartOnlineStorageSegm[] = +{ + 0x4000, 0xa702, 0x0001, 0xa702, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartOnlineStorageTextRect[] = +{ + { { 3600, 0 }, { 18000, 21600 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartOnlineStorageGluePoints[] = +{ + { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 18000, 10800 } +}; +static const mso_CustomShape msoFlowChartOnlineStorage = +{ + const_cast(mso_sptFlowChartOnlineStorageVert), SAL_N_ELEMENTS( mso_sptFlowChartOnlineStorageVert ), + const_cast(mso_sptFlowChartOnlineStorageSegm), sizeof( mso_sptFlowChartOnlineStorageSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartOnlineStorageTextRect), SAL_N_ELEMENTS( mso_sptFlowChartOnlineStorageTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartOnlineStorageGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartOnlineStorageGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartDelayVert[] = +{ + { 10800, 0 }, { 21600, 10800 }, { 10800, 21600 }, { 0, 21600 }, + { 0, 0 } +}; +static const sal_uInt16 mso_sptFlowChartDelaySegm[] = +{ + 0x4000, 0xa702, 0x0002, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartDelayTextRect[] = +{ + { { 0, 3100 }, { 18500, 18500 } } +}; +static const mso_CustomShape msoFlowChartDelay = +{ + const_cast(mso_sptFlowChartDelayVert), SAL_N_ELEMENTS( mso_sptFlowChartDelayVert ), + const_cast(mso_sptFlowChartDelaySegm), sizeof( mso_sptFlowChartDelaySegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartDelayTextRect), SAL_N_ELEMENTS( mso_sptFlowChartDelayTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static 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 +}; +static const sal_uInt16 mso_sptFlowChartMagneticTapeSegm[] = +{ + 0x4000, 0x0002, 0x2004, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartMagneticTapeTextRect[] = +{ + { { 3100, 3100 }, { 18500, 18500 } } +}; +static const mso_CustomShape msoFlowChartMagneticTape = +{ + const_cast(mso_sptFlowChartMagneticTapeVert), SAL_N_ELEMENTS( mso_sptFlowChartMagneticTapeVert ), + const_cast(mso_sptFlowChartMagneticTapeSegm), sizeof( mso_sptFlowChartMagneticTapeSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartMagneticTapeTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMagneticTapeTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartMagneticDiskVert[] = +{ + { 0, 3400 }, { 10800, 0 }, { 21600, 3400 }, { 21600, 18200 }, + { 10800, 21600 }, { 0, 18200 }, + + { 0, 3400 }, { 10800, 6800 }, { 21600, 3400 } +}; +static const sal_uInt16 mso_sptFlowChartMagneticDiskSegm[] = +{ + 0x4000, 0xa802, 0x0001, 0xa802, 0x6000, 0x8000, + 0x4000, 0xa802, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartMagneticDiskTextRect[] = +{ + { { 0, 6800 }, { 21600, 18200 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartMagneticDiskGluePoints[] = +{ + { 10800, 6800 }, { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 21600, 10800 } +}; +static const mso_CustomShape msoFlowChartMagneticDisk = +{ + const_cast(mso_sptFlowChartMagneticDiskVert), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDiskVert ), + const_cast(mso_sptFlowChartMagneticDiskSegm), sizeof( mso_sptFlowChartMagneticDiskSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartMagneticDiskTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDiskTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartMagneticDiskGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDiskGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartMagneticDrumVert[] = +{ + { 18200, 0 }, { 21600, 10800 }, { 18200, 21600 }, { 3400, 21600 }, + { 0, 10800 }, { 3400, 0 }, + + { 18200, 0 }, { 14800, 10800 }, { 18200, 21600 } +}; +static const sal_uInt16 mso_sptFlowChartMagneticDrumSegm[] = +{ + 0x4000, 0xa702, 0x0001, 0xa702, 0x6000, 0x8000, + 0x4000, 0xa702, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartMagneticDrumTextRect[] = +{ + { { 3400, 0 }, { 14800, 21600 } } +}; +static const SvxMSDffVertPair mso_sptFlowChartMagneticDrumGluePoints[] = +{ + { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 14800, 10800 }, { 21600, 10800 } +}; +static const mso_CustomShape msoFlowChartMagneticDrum = +{ + const_cast(mso_sptFlowChartMagneticDrumVert), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDrumVert ), + const_cast(mso_sptFlowChartMagneticDrumSegm), sizeof( mso_sptFlowChartMagneticDrumSegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartMagneticDrumTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDrumTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptFlowChartMagneticDrumGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDrumGluePoints ), + nullptr, 0 // handles +}; + +static const SvxMSDffVertPair mso_sptFlowChartDisplayVert[] = +{ + { 3600, 0 }, { 17800, 0 }, { 21600, 10800 }, { 17800, 21600 }, + { 3600, 21600 }, { 0, 10800 } +}; +static const sal_uInt16 mso_sptFlowChartDisplaySegm[] = +{ + 0x4000, 0x0001, 0xa702, 0x0002, 0x6000, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptFlowChartDisplayTextRect[] = +{ + { { 3600, 0 }, { 17800, 21600 } } +}; +static const mso_CustomShape msoFlowChartDisplay = +{ + const_cast(mso_sptFlowChartDisplayVert), SAL_N_ELEMENTS( mso_sptFlowChartDisplayVert ), + const_cast(mso_sptFlowChartDisplaySegm), sizeof( mso_sptFlowChartDisplaySegm ) >> 1, + nullptr, 0, + nullptr, + const_cast(mso_sptFlowChartDisplayTextRect), SAL_N_ELEMENTS( mso_sptFlowChartDisplayTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ), + nullptr, 0 // handles +}; + +static 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 } +}; +static 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 } } +}; +static const sal_Int32 mso_sptWedgeRectCalloutDefault[] = +{ + 2, 1400, 25920 +}; +static const SvxMSDffTextRectangles mso_sptWedgeRectCalloutTextRect[] = +{ + { { 0, 0 }, { 21600, 21600 } } +}; +static const SvxMSDffVertPair mso_sptWedgeRectCalloutGluePoints[] = +{ + { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 21600, 10800 }, { 40 MSO_I, 41 MSO_I } +}; +static const SvxMSDffHandle mso_sptCalloutHandle[] = +{ + { + SvxMSDffHandleFlags::NONE, + 0x100, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff + } +}; +static const mso_CustomShape msoWedgeRectCallout = +{ + const_cast(mso_sptWedgeRectCalloutVert), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutVert ), + nullptr, 0, + const_cast(mso_sptWedgeRectCalloutCalc), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutCalc ), + const_cast(mso_sptWedgeRectCalloutDefault), + const_cast(mso_sptWedgeRectCalloutTextRect), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptWedgeRectCalloutGluePoints), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutGluePoints ), + const_cast(mso_sptCalloutHandle), SAL_N_ELEMENTS( mso_sptCalloutHandle ) // handles +}; +static 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 } +}; +static const sal_uInt16 mso_sptWedgeRRectCalloutSegm[] = +{ + 0x4000, 0xa701, 0x0005, 0xa801, 0x0005, 0xa701, 0x0005, 0xa801, 0x0004, 0x6001, 0x8000 +}; +static const SvxMSDffTextRectangles mso_sptWedgeRRectCalloutTextRect[] = +{ + { { 800, 800 }, { 20800, 20800 } } +}; +static const mso_CustomShape msoWedgeRRectCallout = +{ + const_cast(mso_sptWedgeRRectCalloutVert), SAL_N_ELEMENTS( mso_sptWedgeRRectCalloutVert ), + const_cast(mso_sptWedgeRRectCalloutSegm), sizeof( mso_sptWedgeRRectCalloutSegm ) >> 1, + const_cast(mso_sptWedgeRectCalloutCalc), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutCalc ), + const_cast(mso_sptWedgeRectCalloutDefault), + const_cast(mso_sptWedgeRRectCalloutTextRect), SAL_N_ELEMENTS( mso_sptWedgeRRectCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle), SAL_N_ELEMENTS( mso_sptCalloutHandle ) // handles +}; +static 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 } +}; +static const sal_uInt16 mso_sptBalloonSegm[] = +{ + 0x4000, 0xa701, 0x0001, 0xa801, 0x0003, 0xa701, 0x0001, 0xa801, 0x6001, 0x8000 +}; +static const SvxMSDffHandle mso_sptBalloonHandle[] = +{ + { + SvxMSDffHandleFlags::RANGE, + 0x100, 1, 10800, 10800, 0, 8990, MIN_INT32, 0x7fffffff + } +}; +static const SvxMSDffTextRectangles mso_sptBalloonTextRect[] = +{ + { { 800, 800 }, { 20800, 17250 } } +}; +static const mso_CustomShape msoBalloon = +{ + const_cast(mso_sptBalloonVert), SAL_N_ELEMENTS( mso_sptBalloonVert ), + const_cast(mso_sptBalloonSegm), sizeof( mso_sptBalloonSegm ) >> 1, + const_cast(mso_sptWedgeRectCalloutCalc), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutCalc ), + const_cast(mso_sptWedgeRectCalloutDefault), + const_cast(mso_sptBalloonTextRect), SAL_N_ELEMENTS( mso_sptBalloonTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptBalloonHandle), SAL_N_ELEMENTS( mso_sptBalloonHandle ) // handles +}; +static 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 } +}; +static const sal_uInt16 mso_sptWedgeEllipseCalloutSegm[] = +{ + 0xa504, 0x0001, 0x6001, 0x8000 +}; +static 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 +}; +static const sal_Int32 mso_sptWedgeEllipseCalloutDefault[] = +{ + 2, 1350, 25920 +}; +static 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 } +}; +static const SvxMSDffTextRectangles mso_sptWedgeEllipseCalloutTextRect[] = +{ + { { 3200, 3200 }, { 18400, 18400 } } +}; +static const mso_CustomShape msoWedgeEllipseCallout = +{ + const_cast(mso_sptWedgeEllipseCalloutVert), SAL_N_ELEMENTS( mso_sptWedgeEllipseCalloutVert ), + const_cast(mso_sptWedgeEllipseCalloutSegm), sizeof( mso_sptWedgeEllipseCalloutSegm ) >> 1, + const_cast(mso_sptWedgeEllipseCalloutCalc), SAL_N_ELEMENTS( mso_sptWedgeEllipseCalloutCalc ), + const_cast(mso_sptWedgeEllipseCalloutDefault), + const_cast(mso_sptWedgeEllipseCalloutTextRect), SAL_N_ELEMENTS( mso_sptWedgeEllipseCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptWedgeEllipseCalloutGluePoints), SAL_N_ELEMENTS( mso_sptWedgeEllipseCalloutGluePoints ), + const_cast(mso_sptCalloutHandle), SAL_N_ELEMENTS( mso_sptCalloutHandle ) // handles +}; + +static 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 +}; +static 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 +}; +static 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 +}; +static const sal_Int32 mso_sptCloudCalloutDefault[] = +{ + 2, 1350, 25920 +}; +static const SvxMSDffTextRectangles mso_sptCloudCalloutTextRect[] = +{ + { { 3000, 3320 }, { 17110, 17330 } } +}; +static const mso_CustomShape msoCloudCallout = +{ + const_cast(mso_sptCloudCalloutVert), SAL_N_ELEMENTS( mso_sptCloudCalloutVert ), + const_cast(mso_sptCloudCalloutSegm), sizeof( mso_sptCloudCalloutSegm ) >> 1, + const_cast(mso_sptCloudCalloutCalc), SAL_N_ELEMENTS( mso_sptCloudCalloutCalc ), + const_cast(mso_sptCloudCalloutDefault), + const_cast(mso_sptCloudCalloutTextRect), SAL_N_ELEMENTS( mso_sptCloudCalloutTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle), SAL_N_ELEMENTS( mso_sptCalloutHandle ) // handles +}; + +static 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 } +}; +static 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 +}; +static const SvxMSDffVertPair mso_sptWaveGluePoints[] = +{ + { 0x12 MSO_I, 0 MSO_I }, { 0x14 MSO_I, 10800 }, { 0x13 MSO_I, 1 MSO_I }, { 0x15 MSO_I, 10800 } +}; +static const sal_uInt16 mso_sptWaveSegm[] = +{ + 0x4000, 0x2001, 0x0001, 0x2001, 0x6000, 0x8000 +}; +static 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 } +}; +static const sal_Int32 mso_sptWaveDefault[] = +{ + 2, 1400, 10800 +}; +static const SvxMSDffTextRectangles mso_sptWaveTextRect[] = +{ + { { 5 MSO_I, 22 MSO_I }, { 11 MSO_I, 23 MSO_I } } +}; +static const mso_CustomShape msoWave = +{ + const_cast(mso_sptWaveVert), SAL_N_ELEMENTS( mso_sptWaveVert ), + const_cast(mso_sptWaveSegm), sizeof( mso_sptWaveSegm ) >> 1, + const_cast(mso_sptWaveCalc), SAL_N_ELEMENTS( mso_sptWaveCalc ), + const_cast(mso_sptWaveDefault), + const_cast(mso_sptWaveTextRect), SAL_N_ELEMENTS( mso_sptWaveTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptWaveGluePoints), SAL_N_ELEMENTS( mso_sptWaveGluePoints ), + const_cast(mso_sptWaveHandle), SAL_N_ELEMENTS( mso_sptWaveHandle ) +}; + +static 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 } +}; +static 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 +}; +static const SvxMSDffVertPair mso_sptDoubleWaveGluePoints[] = +{ + { 0x12 MSO_I, 0 MSO_I }, { 0x14 MSO_I, 10800 }, { 0x13 MSO_I, 1 MSO_I }, { 0x15 MSO_I, 10800 } +}; +static const sal_uInt16 mso_sptDoubleWaveSegm[] = +{ + 0x4000, 0x2002, 0x0001, 0x2002, 0x6000, 0x8000 +}; +static 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 } +}; +static const sal_Int32 mso_sptDoubleWaveDefault[] = +{ + 2, 1400, 10800 +}; +static const SvxMSDffTextRectangles mso_sptDoubleWaveTextRect[] = +{ + { { 5 MSO_I, 22 MSO_I }, { 11 MSO_I, 23 MSO_I } } +}; +static const mso_CustomShape msoDoubleWave = +{ + const_cast(mso_sptDoubleWaveVert), SAL_N_ELEMENTS( mso_sptDoubleWaveVert ), + const_cast(mso_sptDoubleWaveSegm), sizeof( mso_sptDoubleWaveSegm ) >> 1, + const_cast(mso_sptDoubleWaveCalc), SAL_N_ELEMENTS( mso_sptDoubleWaveCalc ), + const_cast(mso_sptDoubleWaveDefault), + const_cast(mso_sptDoubleWaveTextRect), SAL_N_ELEMENTS( mso_sptDoubleWaveTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptDoubleWaveGluePoints), SAL_N_ELEMENTS( mso_sptDoubleWaveGluePoints ), + const_cast(mso_sptDoubleWaveHandle), SAL_N_ELEMENTS( mso_sptDoubleWaveHandle ) +}; + +// for each shapetype a bit of 1 is indicating that the shape is NOT filled by default +static 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(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# +static 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(eSpType); + if ( i < 0x100 ) + bIsStrokedByDefault = ( mso_DefaultStrokingTable[ i >> 4 ] & ( 1 << ( i & 0xf ) ) ) == 0; + return bIsStrokedByDefault; +} + +static 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(eSpType); + if ( i < 0x100 ) + bSortFilledObjectsToBackByDefault = ( msoSortFilledObjectsToBackTable[ i >> 4 ] & ( 1 << ( i & 0xf ) ) ) != 0; + return bSortFilledObjectsToBackByDefault; +} + +static const SvxMSDffTextRectangles mso_sptFontWorkTextRect[] = +{ + { { 0, 0 }, { 21600, 21600 } } +}; + +static const SvxMSDffVertPair mso_sptTextPlainTextVert[] = +{ + { 3 MSO_I, 0 }, { 5 MSO_I, 0 }, { 6 MSO_I, 21600 }, { 7 MSO_I, 21600 } +}; +static 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) +}; +static const sal_uInt16 mso_sptTextPlainTextSegm[] = +{ + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextPlainTextHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 21600, 10800, 10800, 6629, 14971, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoTextPlainText = +{ + const_cast(mso_sptTextPlainTextVert), SAL_N_ELEMENTS( mso_sptTextPlainTextVert ), + const_cast(mso_sptTextPlainTextSegm), sizeof( mso_sptTextPlainTextSegm ) >> 1, + const_cast(mso_sptTextPlainTextCalc), SAL_N_ELEMENTS( mso_sptTextPlainTextCalc ), + const_cast(mso_sptDefault10800), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextPlainTextHandle), SAL_N_ELEMENTS( mso_sptTextPlainTextHandle ) +}; + +static 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 } +}; +static const SvxMSDffCalculationData mso_sptTextStopCalc[] = // adjustment1 : 3080 - 10800 +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, + { 0x8000, { 21600, 0, DFF_Prop_adjustValue } } +}; +static const sal_uInt16 mso_sptTextStopSegm[] = +{ + 0x4000, 0x0003, 0x8000, + 0x4000, 0x0003, 0x8000 +}; +static const sal_Int32 mso_sptTextStopDefault[] = +{ + 1, 2700 +}; +static const SvxMSDffHandle mso_sptTextStopHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 3080, 10800 } +}; +static const mso_CustomShape msoTextStop = +{ + const_cast(mso_sptTextStopVert), SAL_N_ELEMENTS( mso_sptTextStopVert ), + const_cast(mso_sptTextStopSegm), sizeof( mso_sptTextStopSegm ) >> 1, + const_cast(mso_sptTextStopCalc), SAL_N_ELEMENTS( mso_sptTextStopCalc ), + const_cast(mso_sptTextStopDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextStopHandle), SAL_N_ELEMENTS( mso_sptTextStopHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextTriangleVert[] = +{ + { 0, 0 MSO_I }, { 10800, 0 }, { 21600, 0 MSO_I }, { 0, 21600 }, { 21600, 21600 } +}; +static const SvxMSDffCalculationData mso_sptTextTriangleCalc[] = // adjustment1 : 6629 - 14971 +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } } +}; +static const sal_uInt16 mso_sptTextTriangleSegm[] = +{ + 0x4000, 0x0002, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextTriangleHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 21600 } +}; +static const mso_CustomShape msoTextTriangle = +{ + const_cast(mso_sptTextTriangleVert), SAL_N_ELEMENTS( mso_sptTextTriangleVert ), + const_cast(mso_sptTextTriangleSegm), sizeof( mso_sptTextTriangleSegm ) >> 1, + const_cast(mso_sptTextTriangleCalc), SAL_N_ELEMENTS( mso_sptTextTriangleCalc ), + const_cast(mso_sptDefault10800), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextTriangleHandle), SAL_N_ELEMENTS( mso_sptTextTriangleHandle ) +}; +static const SvxMSDffVertPair mso_sptTextTriangleInvertedVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 0, 0 MSO_I }, { 10800, 21600 }, { 21600, 0 MSO_I } +}; +static const sal_uInt16 mso_sptTextTriangleInvertedSegm[] = +{ + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0002, 0x8000 +}; +static const mso_CustomShape msoTextTriangleInverted = +{ + const_cast(mso_sptTextTriangleInvertedVert), SAL_N_ELEMENTS( mso_sptTextTriangleInvertedVert ), + const_cast(mso_sptTextTriangleInvertedSegm), sizeof( mso_sptTextTriangleInvertedSegm ) >> 1, + const_cast(mso_sptTextTriangleCalc), SAL_N_ELEMENTS( mso_sptTextTriangleCalc ), + const_cast(mso_sptDefault10800), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextTriangleHandle), SAL_N_ELEMENTS( mso_sptTextTriangleHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextChevronVert[] = +{ + { 0, 0 MSO_I }, { 10800, 0 }, { 21600, 0 MSO_I }, { 0, 21600 }, { 10800, 1 MSO_I }, { 21600, 21600 } +}; +static const SvxMSDffCalculationData mso_sptTextChevronCalc[] = // adjustment1 : 6629 - 14971 +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, + { 0x8000, { 21600, 0, DFF_Prop_adjustValue } } +}; +static const sal_uInt16 mso_sptTextChevronSegm[] = +{ + 0x4000, 0x0002, 0x8000, + 0x4000, 0x0002, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextChevronHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 } +}; +static const mso_CustomShape msoTextChevron = +{ + const_cast(mso_sptTextChevronVert), SAL_N_ELEMENTS( mso_sptTextChevronVert ), + const_cast(mso_sptTextChevronSegm), sizeof( mso_sptTextChevronSegm ) >> 1, + const_cast(mso_sptTextChevronCalc), SAL_N_ELEMENTS( mso_sptTextChevronCalc ), + const_cast(mso_sptDefault5400), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextChevronHandle), SAL_N_ELEMENTS( mso_sptTextChevronHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextChevronInvertedVert[] = +{ + { 0, 0 }, { 10800, 1 MSO_I }, { 21600, 0 }, { 0, 0 MSO_I }, { 10800, 21600 }, { 21600, 0 MSO_I } +}; +static const SvxMSDffCalculationData mso_sptTextChevronInvertedCalc[] = // adjustment1 : 6629 - 14971 +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, + { 0x8000, { 21600, 0, DFF_Prop_adjustValue } } +}; +static const sal_uInt16 mso_sptTextChevronInvertedSegm[] = +{ + 0x4000, 0x0002, 0x8000, + 0x4000, 0x0002, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextChevronInvertedHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 10800, 21600 } +}; +static const mso_CustomShape msoTextChevronInverted = +{ + const_cast(mso_sptTextChevronInvertedVert), SAL_N_ELEMENTS( mso_sptTextChevronInvertedVert ), + const_cast(mso_sptTextChevronInvertedSegm), sizeof( mso_sptTextChevronInvertedSegm ) >> 1, + const_cast(mso_sptTextChevronInvertedCalc), SAL_N_ELEMENTS( mso_sptTextChevronInvertedCalc ), + const_cast(mso_sptDefault16200), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(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 +static 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 +}; +static 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 +}; +static const sal_uInt16 mso_sptTextRingInsideSegm[] = +{ + 0xa604, 0xa504,0x8000, + 0xa604, 0xa504,0x8000 +}; +static 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 } +}; +static const mso_CustomShape msoTextRingInside = +{ + const_cast(mso_sptTextRingInsideVert), SAL_N_ELEMENTS( mso_sptTextRingInsideVert ), + const_cast(mso_sptTextRingInsideSegm), sizeof( mso_sptTextRingInsideSegm ) >> 1, + const_cast(mso_sptTextRingInsideCalc), SAL_N_ELEMENTS( mso_sptTextRingInsideCalc ), + const_cast(mso_sptDefault13500), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(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. +static const SvxMSDffVertPair mso_sptTextRingOutsideVert[] = +{ + { 10800, 0 MSO_I }, { 10800, 0 MSO_I }, { 180, 359 }, + { 10800, 1 MSO_I }, { 10800, 0 MSO_I }, { 180, 359 } +}; +static const SvxMSDffCalculationData mso_sptTextRingOutsideCalc[] = // adjustment1 : 6629 - 14971 +{ + { 0x2001, { DFF_Prop_adjustValue, 1, 2 } }, + { 0x8000, { 21600, 0, 0x400 } } +}; +static const sal_uInt16 mso_sptTextRingOutsideSegm[] = +{ + 0xA203, 0x8000, + 0xA203, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextRingOutsideHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 10800, 21600 } +}; +static const mso_CustomShape msoTextRingOutside = +{ + const_cast(mso_sptTextRingOutsideVert), SAL_N_ELEMENTS( mso_sptTextRingOutsideVert ), + const_cast(mso_sptTextRingOutsideSegm), sizeof( mso_sptTextRingOutsideSegm ) >> 1, + const_cast(mso_sptTextRingOutsideCalc), SAL_N_ELEMENTS( mso_sptTextRingOutsideCalc ), + const_cast(mso_sptDefault13500), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextRingOutsideHandle), SAL_N_ELEMENTS( mso_sptTextRingOutsideHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextFadeRightVert[] = +{ + { 0, 0 }, { 21600, 0 MSO_I }, { 0, 21600 }, { 21600, 1 MSO_I } +}; +static const SvxMSDffCalculationData mso_sptTextFadeCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, + { 0x8000, { 21600, 0, DFF_Prop_adjustValue } } +}; +static const sal_uInt16 mso_sptTextFadeSegm[] = +{ + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextFadeRightHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 21600, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 } +}; +static const mso_CustomShape msoTextFadeRight = +{ + const_cast(mso_sptTextFadeRightVert), SAL_N_ELEMENTS( mso_sptTextFadeRightVert ), + const_cast(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1, + const_cast(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ), + const_cast(mso_sptDefault7200), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextFadeRightHandle), SAL_N_ELEMENTS( mso_sptTextFadeRightHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextFadeLeftVert[] = +{ + { 0, 0 MSO_I }, { 21600, 0 }, { 0, 1 MSO_I }, { 21600, 21600 } +}; +static const SvxMSDffHandle mso_sptTextFadeLeftHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 } +}; +static const mso_CustomShape msoTextFadeLeft = +{ + const_cast(mso_sptTextFadeLeftVert), SAL_N_ELEMENTS( mso_sptTextFadeLeftVert ), + const_cast(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1, + const_cast(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ), + const_cast(mso_sptDefault7200), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextFadeLeftHandle), SAL_N_ELEMENTS( mso_sptTextFadeLeftHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextFadeUpVert[] = +{ + { 0 MSO_I, 0 }, { 1 MSO_I, 0 }, { 0, 21600 }, { 21600, 21600 } +}; +static const SvxMSDffHandle mso_sptTextFadeUpHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoTextFadeUp = +{ + const_cast(mso_sptTextFadeUpVert), SAL_N_ELEMENTS( mso_sptTextFadeUpVert ), + const_cast(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1, + const_cast(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ), + const_cast(mso_sptDefault7200), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextFadeUpHandle), SAL_N_ELEMENTS( mso_sptTextFadeUpHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextFadeDownVert[] = +{ + { 0, 0 }, { 21600, 0 }, { 0 MSO_I, 21600 }, { 1 MSO_I, 21600 } +}; +static const SvxMSDffHandle mso_sptTextFadeDownHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 21600, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoTextFadeDown = +{ + const_cast(mso_sptTextFadeDownVert), SAL_N_ELEMENTS( mso_sptTextFadeDownVert ), + const_cast(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1, + const_cast(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ), + const_cast(mso_sptDefault7200), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextFadeDownHandle), SAL_N_ELEMENTS( mso_sptTextFadeDownHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextSlantUpVert[] = +{ + { 0, 0 MSO_I }, { 21600, 0 }, { 0, 21600 }, { 21600, 1 MSO_I } +}; +static const SvxMSDffHandle mso_sptTextSlantUpHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 15400 } +}; +static const mso_CustomShape msoTextSlantUp = +{ + const_cast(mso_sptTextSlantUpVert), SAL_N_ELEMENTS( mso_sptTextSlantUpVert ), + const_cast(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1, + const_cast(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ), + const_cast(mso_sptDefault12000), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextSlantUpHandle), SAL_N_ELEMENTS( mso_sptTextSlantUpHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextSlantDownVert[] = +{ + { 0, 0 }, { 21600, 1 MSO_I }, { 0, 0 MSO_I }, { 21600, 21600 } +}; +static const SvxMSDffHandle mso_sptTextSlantDownHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 6200, 21600 } +}; +static const mso_CustomShape msoTextSlantDown = +{ + const_cast(mso_sptTextSlantDownVert), SAL_N_ELEMENTS( mso_sptTextSlantDownVert ), + const_cast(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1, + const_cast(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ), + const_cast(mso_sptDefault12000), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextSlantDownHandle), SAL_N_ELEMENTS( mso_sptTextSlantDownHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextCascadeUpVert[] = +{ + { 0, 2 MSO_I }, { 21600, 0 }, { 0, 21600 }, { 21600, 0 MSO_I } +}; +static const SvxMSDffCalculationData mso_sptTextCascadeCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, + { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }, + { 0x2001, { 0x401, 1, 4 } } +}; +static const SvxMSDffHandle mso_sptTextCascadeUpHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 21600, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 6200, 21600 } +}; +static const mso_CustomShape msoTextCascadeUp = +{ + const_cast(mso_sptTextCascadeUpVert), SAL_N_ELEMENTS( mso_sptTextCascadeUpVert ), + const_cast(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1, + const_cast(mso_sptTextCascadeCalc), SAL_N_ELEMENTS( mso_sptTextCascadeCalc ), + const_cast(mso_sptDefault9600), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextCascadeUpHandle), SAL_N_ELEMENTS( mso_sptTextCascadeUpHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextCascadeDownVert[] = +{ + { 0, 0 }, { 21600, 2 MSO_I }, { 0, 0 MSO_I }, { 21600, 21600 } +}; +static const SvxMSDffHandle mso_sptTextCascadeDownHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 6200, 21600 } +}; +static const mso_CustomShape msoTextCascadeDown = +{ + const_cast(mso_sptTextCascadeDownVert), SAL_N_ELEMENTS( mso_sptTextCascadeDownVert ), + const_cast(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1, + const_cast(mso_sptTextCascadeCalc), SAL_N_ELEMENTS( mso_sptTextCascadeCalc ), + const_cast(mso_sptDefault9600), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextCascadeDownHandle), SAL_N_ELEMENTS( mso_sptTextCascadeDownHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextArchUpCurveVert[] = +{ + { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 3 MSO_I }, { 4 MSO_I, 3 MSO_I } +}; +static 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 } } +}; +static const sal_uInt16 mso_sptTextArchUpCurveSegm[] = +{ + 0xA504, 0x8000 // clockwise arc +}; +static const SvxMSDffHandle mso_sptTextArchUpCurveHandle[] = +{ + { SvxMSDffHandleFlags::POLAR, + 10800, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const sal_Int32 mso_sptTextArchUpCurveDefault[] = +{ + 1, 180 +}; +static const mso_CustomShape msoTextArchUpCurve = +{ + const_cast(mso_sptTextArchUpCurveVert), SAL_N_ELEMENTS( mso_sptTextArchUpCurveVert ), + const_cast(mso_sptTextArchUpCurveSegm), sizeof( mso_sptTextArchUpCurveSegm ) >> 1, + const_cast(mso_sptTextArchCurveCalc), SAL_N_ELEMENTS( mso_sptTextArchCurveCalc ), + const_cast(mso_sptTextArchUpCurveDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextArchUpCurveHandle), SAL_N_ELEMENTS( mso_sptTextArchUpCurveHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextArchDownCurveVert[] = +{ + { 0, 0 }, { 21600, 21600 }, { 4 MSO_I, 3 MSO_I }, { 2 MSO_I, 3 MSO_I } +}; +static const sal_uInt16 mso_sptTextArchDownCurveSegm[] = +{ + 0xA304, 0x8000 // counter clockwise arc to +}; +static const SvxMSDffHandle mso_sptTextArchDownCurveHandle[] = +{ + { SvxMSDffHandleFlags::POLAR, + 10800, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const sal_Int32 mso_sptTextArchDownCurveDefault[] = +{ + 1, 0 +}; +static const mso_CustomShape msoTextArchDownCurve = +{ + const_cast(mso_sptTextArchDownCurveVert), SAL_N_ELEMENTS( mso_sptTextArchDownCurveVert ), + const_cast(mso_sptTextArchDownCurveSegm), sizeof( mso_sptTextArchDownCurveSegm ) >> 1, + const_cast(mso_sptTextArchCurveCalc), SAL_N_ELEMENTS( mso_sptTextArchCurveCalc ), + const_cast(mso_sptTextArchDownCurveDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextArchDownCurveHandle), SAL_N_ELEMENTS( mso_sptTextArchDownCurveHandle ) +}; + +static const SvxMSDffVertPair mso_sptTextCircleCurveVert[] = +{ + { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 3 MSO_I }, { 2 MSO_I, 4 MSO_I } +}; +static 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 } } +}; +static const sal_uInt16 mso_sptTextCircleCurveSegm[] = +{ + 0xA504, 0x8000 // clockwise arc to +}; +static const SvxMSDffHandle mso_sptTextCircleCurveHandle[] = +{ + { SvxMSDffHandleFlags::POLAR, + 10800, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const sal_Int32 mso_sptTextCircleCurveDefault[] = +{ + 1, -179 +}; +static const mso_CustomShape msoTextCircleCurve = +{ + const_cast(mso_sptTextCircleCurveVert), SAL_N_ELEMENTS( mso_sptTextCircleCurveVert ), + const_cast(mso_sptTextCircleCurveSegm), sizeof( mso_sptTextCircleCurveSegm ) >> 1, + const_cast(mso_sptTextCircleCurveCalc), SAL_N_ELEMENTS( mso_sptTextCircleCurveCalc ), + const_cast(mso_sptTextCircleCurveDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextCircleCurveHandle), SAL_N_ELEMENTS( mso_sptTextCircleCurveHandle ) +}; + +static 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 } +}; +static 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 } } +}; +static const sal_uInt16 mso_sptTextButtonCurveSegm[] = +{ + 0xA504, 0x8000, // clockwise arc + 0x4000, 0x0001, 0x8000, + 0xA304, 0x8000 // counter clockwise +}; +static const SvxMSDffHandle mso_sptTextButtonCurveHandle[] = +{ + { SvxMSDffHandleFlags::POLAR, + 10800, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const sal_Int32 mso_sptTextButtonCurveDefault[] = +{ + 1, 180 +}; +static const mso_CustomShape msoTextButtonCurve = +{ + const_cast(mso_sptTextButtonCurveVert), SAL_N_ELEMENTS( mso_sptTextButtonCurveVert ), + const_cast(mso_sptTextButtonCurveSegm), sizeof( mso_sptTextButtonCurveSegm ) >> 1, + const_cast(mso_sptTextButtonCurveCalc), SAL_N_ELEMENTS( mso_sptTextButtonCurveCalc ), + const_cast(mso_sptTextButtonCurveDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextButtonCurveHandle), SAL_N_ELEMENTS( mso_sptTextButtonCurveHandle ) +}; + +static 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 } +}; +static 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 } } +}; +static const sal_uInt16 mso_sptTextArchUpPourSegm[] = +{ + 0xA504, 0x8000, 0xA504, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextArchPourHandle[] = +{ + { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE, + 0x101, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const sal_Int32 mso_sptTextArchUpPourDefault[] = +{ + 2, 180, 5400 +}; +static const mso_CustomShape msoTextArchUpPour = +{ + const_cast(mso_sptTextArchUpPourVert), SAL_N_ELEMENTS( mso_sptTextArchUpPourVert ), + const_cast(mso_sptTextArchUpPourSegm), sizeof( mso_sptTextArchUpPourSegm ) >> 1, + const_cast(mso_sptTextArchPourCalc), SAL_N_ELEMENTS( mso_sptTextArchPourCalc ), + const_cast(mso_sptTextArchUpPourDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextArchPourHandle), SAL_N_ELEMENTS( mso_sptTextArchPourHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptTextArchDownPourSegm[] = +{ + 0xA304, 0x8000, 0xA304, 0x8000 +}; +static const sal_Int32 mso_sptTextArchDownPourDefault[] = +{ + 2, 0, 5400 +}; +static const mso_CustomShape msoTextArchDownPour = +{ + const_cast(mso_sptTextArchDownPourVert), SAL_N_ELEMENTS( mso_sptTextArchDownPourVert ), + const_cast(mso_sptTextArchDownPourSegm), sizeof( mso_sptTextArchDownPourSegm ) >> 1, + const_cast(mso_sptTextArchPourCalc), SAL_N_ELEMENTS( mso_sptTextArchPourCalc ), + const_cast(mso_sptTextArchDownPourDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextArchPourHandle), SAL_N_ELEMENTS( mso_sptTextArchPourHandle ) +}; + +static 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 } +}; +static 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 } } +}; +static const sal_uInt16 mso_sptTextCirclePourSegm[] = +{ + 0xA504, 0x8000, 0xA504, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextCirclePourHandle[] = +{ + { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE, + 0x101, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff } +}; +static const sal_Int32 mso_sptTextCirclePourDefault[] = +{ + 2, -179, 5400 +}; +static const mso_CustomShape msoTextCirclePour = +{ + const_cast(mso_sptTextCirclePourVert), SAL_N_ELEMENTS( mso_sptTextCirclePourVert ), + const_cast(mso_sptTextCirclePourSegm), sizeof( mso_sptTextCirclePourSegm ) >> 1, + const_cast(mso_sptTextCirclePourCalc), SAL_N_ELEMENTS( mso_sptTextCirclePourCalc ), + const_cast(mso_sptTextCirclePourDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextCirclePourHandle), SAL_N_ELEMENTS( mso_sptTextCirclePourHandle ) +}; + +static 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 } +}; +static 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 +}; +static 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 +}; +static const SvxMSDffHandle mso_sptTextButtonPourHandle[] = +{ + { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE, + 0x101, 0x100, 10800, 10800, 4320, 10800, MIN_INT32, 0x7fffffff } +}; +static const sal_Int32 mso_sptTextButtonPourDefault[] = +{ + 2, 180, 5400 +}; +static const mso_CustomShape msoTextButtonPour = +{ + const_cast(mso_sptTextButtonPourVert), SAL_N_ELEMENTS( mso_sptTextButtonPourVert ), + const_cast(mso_sptTextButtonPourSegm), sizeof( mso_sptTextButtonPourSegm ) >> 1, + const_cast(mso_sptTextButtonPourCalc), SAL_N_ELEMENTS( mso_sptTextButtonPourCalc ), + const_cast(mso_sptTextButtonPourDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextButtonPourHandle), SAL_N_ELEMENTS( mso_sptTextButtonPourHandle ) +}; + +static 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*/ } +}; +static 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 +}; +static const sal_uInt16 mso_sptTextCurveUpSegm[] = +{ + 0x4000, 0x2001, 0x8000, + 0x4000, 0x2002, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextCurveUpHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 12170 } +}; +static const sal_Int32 mso_sptTextCurveUpDefault[] = +{ + 1, 9900 +}; +static const mso_CustomShape msoTextCurveUp = +{ + const_cast(mso_sptTextCurveUpVert), SAL_N_ELEMENTS( mso_sptTextCurveUpVert ), + const_cast(mso_sptTextCurveUpSegm), sizeof( mso_sptTextCurveUpSegm ) >> 1, + const_cast(mso_sptTextCurveUpCalc), SAL_N_ELEMENTS( mso_sptTextCurveUpCalc ), + const_cast(mso_sptTextCurveUpDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextCurveUpHandle), SAL_N_ELEMENTS( mso_sptTextCurveUpHandle ) +}; + +static 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 } +}; +static const SvxMSDffHandle mso_sptTextCurveDownHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 21600, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 12170 } +}; +static const mso_CustomShape msoTextCurveDown = +{ + const_cast(mso_sptTextCurveDownVert), SAL_N_ELEMENTS( mso_sptTextCurveDownVert ), + const_cast(mso_sptTextCurveUpSegm), sizeof( mso_sptTextCurveUpSegm ) >> 1, + const_cast(mso_sptTextCurveUpCalc), SAL_N_ELEMENTS( mso_sptTextCurveUpCalc ), + const_cast(mso_sptTextCurveUpDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextCurveDownHandle), SAL_N_ELEMENTS( mso_sptTextCurveDownHandle ) +}; + +static 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 } +}; +static 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 +}; +static const sal_uInt16 mso_sptTextCanUpSegm[] = +{ + 0x4000, 0x2002, 0x8000, + 0x4000, 0x2002, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextCanUpHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 14400, 21600 } +}; +static const sal_Int32 mso_sptTextCanUpDefault[] = +{ + 1, 18500 +}; +static const mso_CustomShape msoTextCanUp = +{ + const_cast(mso_sptTextCanUpVert), SAL_N_ELEMENTS( mso_sptTextCanUpVert ), + const_cast(mso_sptTextCanUpSegm), sizeof( mso_sptTextCanUpSegm ) >> 1, + const_cast(mso_sptTextCanUpCalc), SAL_N_ELEMENTS( mso_sptTextCanUpCalc ), + const_cast(mso_sptTextCanUpDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextCanUpHandle), SAL_N_ELEMENTS( mso_sptTextCanUpHandle ) +}; + +static 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 } +}; +static const SvxMSDffCalculationData mso_sptTextCanDownCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400 + { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }, // 401 + { 0x4001, { 5470, 0x400, 7200 } } // 402 +}; +static const SvxMSDffHandle mso_sptTextCanDownHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 7200 } +}; +static const sal_Int32 mso_sptTextCanDownDefault[] = +{ + 1, 3100 +}; +static const mso_CustomShape msoTextCanDown = +{ + const_cast(mso_sptTextCanDownVert), SAL_N_ELEMENTS( mso_sptTextCanDownVert ), + const_cast(mso_sptTextCanUpSegm), sizeof( mso_sptTextCanUpSegm ) >> 1, + const_cast(mso_sptTextCanDownCalc), SAL_N_ELEMENTS( mso_sptTextCanDownCalc ), + const_cast(mso_sptTextCanDownDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextCanDownHandle), SAL_N_ELEMENTS( mso_sptTextCanDownHandle ) +}; + +static 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 } +}; +static 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 +}; +static const SvxMSDffHandle mso_sptTextInflateHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 4650 } +}; +static const sal_Int32 mso_sptTextInflateDefault[] = +{ + 1, 2950 +}; +static const mso_CustomShape msoTextInflate = +{ + const_cast(mso_sptTextInflateVert), SAL_N_ELEMENTS( mso_sptTextInflateVert ), + const_cast(mso_sptTextCanUpSegm), sizeof( mso_sptTextCanUpSegm ) >> 1, + const_cast(mso_sptTextInflateCalc), SAL_N_ELEMENTS( mso_sptTextInflateCalc ), + const_cast(mso_sptTextInflateDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextInflateHandle), SAL_N_ELEMENTS( mso_sptTextInflateHandle ) +}; + +static 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 } +}; +static 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 +}; +static const SvxMSDffHandle mso_sptTextDeflateHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 8100 } +}; +static const mso_CustomShape msoTextDeflate = +{ + const_cast(mso_sptTextDeflateVert), SAL_N_ELEMENTS( mso_sptTextDeflateVert ), + const_cast(mso_sptTextCanUpSegm), sizeof( mso_sptTextCanUpSegm ) >> 1, + const_cast(mso_sptTextDeflateCalc), SAL_N_ELEMENTS( mso_sptTextDeflateCalc ), + const_cast(mso_sptDefault8100), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextDeflateHandle), SAL_N_ELEMENTS( mso_sptTextDeflateHandle ) +}; + +static 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 } +}; +static 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 +}; +static const sal_uInt16 mso_sptTextInflateBottomSegm[] = +{ + 0x4000, 0x0001, 0x8000, + 0x4000, 0x2002, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextInflateBottomHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 11150, 21600 } +}; +static const sal_Int32 mso_sptTextInflateBottomDefault[] = +{ + 1, 14700 +}; +static const mso_CustomShape msoTextInflateBottom = +{ + const_cast(mso_sptTextInflateBottomVert), SAL_N_ELEMENTS( mso_sptTextInflateBottomVert ), + const_cast(mso_sptTextInflateBottomSegm), sizeof( mso_sptTextInflateBottomSegm ) >> 1, + const_cast(mso_sptTextInflateBottomCalc), SAL_N_ELEMENTS( mso_sptTextInflateBottomCalc ), + const_cast(mso_sptTextInflateBottomDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextInflateBottomHandle), SAL_N_ELEMENTS( mso_sptTextInflateBottomHandle ) +}; + +static 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 } +}; +static 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 +}; +static const sal_uInt16 mso_sptTextDeflateBottomSegm[] = +{ + 0x4000, 0x0001, 0x8000, + 0x4000, 0x2002, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextDeflateBottomHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 1350, 21600 } +}; +static const sal_Int32 mso_sptTextDeflateBottomDefault[] = +{ + 1, 11500 +}; +static const mso_CustomShape msoTextDeflateBottom = +{ + const_cast(mso_sptTextDeflateBottomVert), SAL_N_ELEMENTS( mso_sptTextDeflateBottomVert ), + const_cast(mso_sptTextDeflateBottomSegm), sizeof( mso_sptTextDeflateBottomSegm ) >> 1, + const_cast(mso_sptTextDeflateBottomCalc), SAL_N_ELEMENTS( mso_sptTextDeflateBottomCalc ), + const_cast(mso_sptTextDeflateBottomDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextDeflateBottomHandle), SAL_N_ELEMENTS( mso_sptTextDeflateBottomHandle ) +}; + +static 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 } +}; +static const SvxMSDffCalculationData mso_sptTextInflateTopCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400 + { 0x2001, { 0x400, 3900, 10450 } } // 401 +}; +static const sal_uInt16 mso_sptTextInflateTopSegm[] = +{ + 0x4000, 0x2002, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextInflateTopHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10450 } +}; +static const sal_Int32 mso_sptTextInflateTopDefault[] = +{ + 1, 6900 +}; +static const mso_CustomShape msoTextInflateTop = +{ + const_cast(mso_sptTextInflateTopVert), SAL_N_ELEMENTS( mso_sptTextInflateTopVert ), + const_cast(mso_sptTextInflateTopSegm), sizeof( mso_sptTextInflateTopSegm ) >> 1, + const_cast(mso_sptTextInflateTopCalc), SAL_N_ELEMENTS( mso_sptTextInflateTopCalc ), + const_cast(mso_sptTextInflateTopDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextInflateTopHandle), SAL_N_ELEMENTS( mso_sptTextInflateTopHandle ) +}; + +static 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 } +}; +static const SvxMSDffCalculationData mso_sptTextDeflateTopCalc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400 + { 0x2001, { 0x400, 12070, 20250 } } // 402 +}; +static const sal_uInt16 mso_sptTextDeflateTopSegm[] = +{ + 0x4000, 0x2002, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextDeflateTopHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 20250 } +}; +static const sal_Int32 mso_sptTextDeflateTopDefault[] = +{ + 1, 10100 +}; +static const mso_CustomShape msoTextDeflateTop = +{ + const_cast(mso_sptTextDeflateTopVert), SAL_N_ELEMENTS( mso_sptTextDeflateTopVert ), + const_cast(mso_sptTextDeflateTopSegm), sizeof( mso_sptTextDeflateTopSegm ) >> 1, + const_cast(mso_sptTextDeflateTopCalc), SAL_N_ELEMENTS( mso_sptTextDeflateTopCalc ), + const_cast(mso_sptTextDeflateTopDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextDeflateTopHandle), SAL_N_ELEMENTS( mso_sptTextDeflateTopHandle ) +}; + +static 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 } +}; +static 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 +}; +static const sal_uInt16 mso_sptTextDeflateInflateSegm[] = +{ + 0x4000, 0x0001, 0x8000, + 0x4000, 0x2002, 0x8000, + 0x4000, 0x2002, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextDeflateInflateHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 1300, 20300 } +}; +static const sal_Int32 mso_sptTextDeflateInflateDefault[] = +{ + 1, 6500 +}; +static const mso_CustomShape msoTextDeflateInflate = +{ + const_cast(mso_sptTextDeflateInflateVert), SAL_N_ELEMENTS( mso_sptTextDeflateInflateVert ), + const_cast(mso_sptTextDeflateInflateSegm), sizeof( mso_sptTextDeflateInflateSegm ) >> 1, + const_cast(mso_sptTextDeflateInflateCalc), SAL_N_ELEMENTS( mso_sptTextDeflateInflateCalc ), + const_cast(mso_sptTextDeflateInflateDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextDeflateInflateHandle), SAL_N_ELEMENTS( mso_sptTextDeflateInflateHandle ) +}; + +static 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 } +}; +static 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 +}; +static const sal_uInt16 mso_sptTextDeflateInflateDeflateSegm[] = +{ + 0x4000, 0x0001, 0x8000, + 0x4000, 0x2002, 0x8000, + 0x4000, 0x2002, 0x8000, + 0x4000, 0x2002, 0x8000, + 0x4000, 0x2002, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const SvxMSDffHandle mso_sptTextDeflateInflateDeflateHandle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 850, 9550 } +}; +static const sal_Int32 mso_sptTextDeflateInflateDeflateDefault[] = +{ + 1, 6050 +}; +static const mso_CustomShape msoTextDeflateInflateDeflate = +{ + const_cast(mso_sptTextDeflateInflateDeflateVert), SAL_N_ELEMENTS( mso_sptTextDeflateInflateDeflateVert ), + const_cast(mso_sptTextDeflateInflateDeflateSegm), sizeof( mso_sptTextDeflateInflateDeflateSegm ) >> 1, + const_cast(mso_sptTextDeflateInflateDeflateCalc), SAL_N_ELEMENTS( mso_sptTextDeflateInflateDeflateCalc ), + const_cast(mso_sptTextDeflateInflateDeflateDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptTextDeflateInflateDeflateHandle), SAL_N_ELEMENTS( mso_sptTextDeflateInflateDeflateHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptTextWave1Segm[] = +{ + 0x4000, 0x2001, 0x8000, + 0x4000, 0x2001, 0x8000 +}; +static const mso_CustomShape msoTextWave1 = +{ + const_cast(mso_sptTextWave1Vert), SAL_N_ELEMENTS( mso_sptTextWave1Vert ), + const_cast(mso_sptTextWave1Segm), sizeof( mso_sptTextWave1Segm ) >> 1, + const_cast(mso_sptWaveCalc), SAL_N_ELEMENTS( mso_sptWaveCalc ), + const_cast(mso_sptWaveDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptWaveGluePoints), SAL_N_ELEMENTS( mso_sptWaveGluePoints ), + const_cast(mso_sptWaveHandle), SAL_N_ELEMENTS( mso_sptWaveHandle ) +}; + +static 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 } +}; +static const mso_CustomShape msoTextWave2 = +{ + const_cast(mso_sptTextWave2Vert), SAL_N_ELEMENTS( mso_sptTextWave2Vert ), + const_cast(mso_sptTextWave1Segm), sizeof( mso_sptTextWave1Segm ) >> 1, + const_cast(mso_sptWaveCalc), SAL_N_ELEMENTS( mso_sptWaveCalc ), + const_cast(mso_sptWaveDefault), + const_cast(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptWaveGluePoints), SAL_N_ELEMENTS( mso_sptWaveGluePoints ), + const_cast(mso_sptWaveHandle), SAL_N_ELEMENTS( mso_sptWaveHandle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptTextWave3Segm[] = +{ + 0x4000, 0x2002, 0x8000, + 0x4000, 0x2002, 0x8000 +}; +static const mso_CustomShape msoTextWave3 = +{ + const_cast(mso_sptTextWave3Vert), SAL_N_ELEMENTS( mso_sptTextWave3Vert ), + const_cast(mso_sptTextWave3Segm), sizeof( mso_sptTextWave3Segm ) >> 1, + const_cast(mso_sptDoubleWaveCalc), SAL_N_ELEMENTS( mso_sptDoubleWaveCalc ), + const_cast(mso_sptDoubleWaveDefault), + const_cast(mso_sptDoubleWaveTextRect), SAL_N_ELEMENTS( mso_sptDoubleWaveTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptDoubleWaveGluePoints), SAL_N_ELEMENTS( mso_sptDoubleWaveGluePoints ), + const_cast(mso_sptDoubleWaveHandle), SAL_N_ELEMENTS( mso_sptDoubleWaveHandle ) +}; + +static 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 } +}; +static const mso_CustomShape msoTextWave4 = +{ + const_cast(mso_sptTextWave4Vert), SAL_N_ELEMENTS( mso_sptTextWave4Vert ), + const_cast(mso_sptTextWave3Segm), sizeof( mso_sptTextWave3Segm ) >> 1, + const_cast(mso_sptDoubleWaveCalc), SAL_N_ELEMENTS( mso_sptDoubleWaveCalc ), + const_cast(mso_sptDoubleWaveDefault), + const_cast(mso_sptDoubleWaveTextRect), SAL_N_ELEMENTS( mso_sptDoubleWaveTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + const_cast(mso_sptDoubleWaveGluePoints), SAL_N_ELEMENTS( mso_sptDoubleWaveGluePoints ), + const_cast(mso_sptDoubleWaveHandle), SAL_N_ELEMENTS( mso_sptDoubleWaveHandle ) +}; + +static const sal_Int32 mso_sptCalloutDefault1[] = +{ + 4, -1800, 24500, -1800, 4000 +}; +static const sal_Int32 mso_sptCalloutDefault2[] = +{ + 4, -8300, 24500, -1800, 4000 +}; +static const sal_Int32 mso_sptCalloutDefault3[] = +{ + 6, -10000, 24500, -3600, 4000, -1800, 4000 +}; +static const sal_Int32 mso_sptCalloutDefault4[] = +{ + 8, 23400, 24500, 25200, 21600, 25200, 4000, 23400, 4000 +}; +static const SvxMSDffVertPair mso_sptCalloutVert1[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I } +}; +static 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 } +}; +static const sal_uInt16 mso_sptCalloutSegm1a[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const sal_uInt16 mso_sptCalloutSegm1b[] = +{ + 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE + 0x4000, 0x0001, 0x8000 +}; +static 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 } +}; +static const sal_uInt16 mso_sptCallout1Segm1a[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const sal_uInt16 mso_sptCallout1Segm1b[] = +{ + 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static 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 } +}; +static 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 } +}; +static 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 } +}; +static const sal_uInt16 mso_sptCallout2Segm1a[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const sal_uInt16 mso_sptCallout2Segm1b[] = +{ + 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const sal_uInt16 mso_sptCallout2Segm1c[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static const sal_uInt16 mso_sptCallout2Segm1d[] = +{ + 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000, + 0x4000, 0x0001, 0x8000 +}; +static 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 } +}; +static 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 } +}; +static 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 } +}; +static const sal_uInt16 mso_sptCallout3Segm1a[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0xaa00, 0x0003, 0x8000 // NO_FILL +}; +static const sal_uInt16 mso_sptCallout3Segm1b[] = +{ + 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE + 0x4000, 0xaa00, 0x0003, 0x8000 // NO FILL +}; +static const sal_uInt16 mso_sptCallout3Segm1c[] = +{ + 0x4000, 0x0003, 0x6000, 0x8000, + 0x4000, 0xaa00, 0x0003, 0x8000, // NO FILL + 0x4000, 0x0001, 0x8000 +}; +static const sal_uInt16 mso_sptCallout3Segm1d[] = +{ + 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE + 0x4000, 0xaa00, 0x0003, 0x8000, // NO FILL + 0x4000, 0x0001, 0x8000 +}; + +static 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 } } +}; + +static const mso_CustomShape msoCallout90 = +{ + const_cast(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ), + const_cast(mso_sptCalloutSegm1b), sizeof( mso_sptCalloutSegm1b ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault1), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 ) +}; +static const mso_CustomShape msoCallout1 = +{ + const_cast(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ), + const_cast(mso_sptCalloutSegm1b), sizeof( mso_sptCalloutSegm1b ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault2), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 ) +}; +static const mso_CustomShape msoCallout2 = +{ + const_cast(mso_sptCallout2Verta), SAL_N_ELEMENTS( mso_sptCallout2Verta ), + const_cast(mso_sptCallout2Segm1b), sizeof( mso_sptCallout2Segm1b ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault3), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle2), SAL_N_ELEMENTS( mso_sptCalloutHandle2 ) +}; +static const mso_CustomShape msoCallout3 = +{ + const_cast(mso_sptCallout3Verta), SAL_N_ELEMENTS( mso_sptCallout3Verta ), + const_cast(mso_sptCallout3Segm1b), sizeof( mso_sptCallout3Segm1b ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault4), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle3), SAL_N_ELEMENTS( mso_sptCalloutHandle3 ) +}; +static const mso_CustomShape msoAccentCallout90 = +{ + const_cast(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ), + const_cast(mso_sptCalloutSegm1b), sizeof( mso_sptCalloutSegm1b ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault1), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 ) +}; +static const mso_CustomShape msoAccentCallout1 = +{ + const_cast(mso_sptCallout1Vert), SAL_N_ELEMENTS( mso_sptCallout1Vert ), + const_cast(mso_sptCallout1Segm1b), sizeof( mso_sptCallout1Segm1b ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault2), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 ) +}; +static const mso_CustomShape msoAccentCallout2 = +{ + const_cast(mso_sptCallout2Vertb), SAL_N_ELEMENTS( mso_sptCallout2Vertb ), + const_cast(mso_sptCallout2Segm1d), sizeof( mso_sptCallout2Segm1d ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault3), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle2), SAL_N_ELEMENTS( mso_sptCalloutHandle2 ) +}; +static const mso_CustomShape msoAccentCallout3 = +{ + const_cast(mso_sptCallout3Vertb), SAL_N_ELEMENTS( mso_sptCallout3Vertb ), + const_cast(mso_sptCallout3Segm1d), sizeof( mso_sptCallout3Segm1d ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault4), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle3), SAL_N_ELEMENTS( mso_sptCalloutHandle3 ) +}; +static const mso_CustomShape msoBorderCallout90 = +{ + const_cast(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ), + const_cast(mso_sptCalloutSegm1a), sizeof( mso_sptCalloutSegm1a ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault1), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 ) +}; +static const mso_CustomShape msoBorderCallout1 = +{ + const_cast(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ), + const_cast(mso_sptCalloutSegm1a), sizeof( mso_sptCalloutSegm1a ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault2), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 ) +}; +static const mso_CustomShape msoBorderCallout2 = +{ + const_cast(mso_sptCallout2Verta), SAL_N_ELEMENTS( mso_sptCallout2Verta ), + const_cast(mso_sptCallout2Segm1a), sizeof( mso_sptCallout2Segm1a ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault3), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle2), SAL_N_ELEMENTS( mso_sptCalloutHandle2 ) +}; +static const mso_CustomShape msoBorderCallout3 = +{ + const_cast(mso_sptCallout3Verta), SAL_N_ELEMENTS( mso_sptCallout3Verta ), + const_cast(mso_sptCallout3Segm1a), sizeof( mso_sptCallout3Segm1a ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault4), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle3), SAL_N_ELEMENTS( mso_sptCalloutHandle3 ) +}; +static const mso_CustomShape msoAccentBorderCallout90 = +{ + const_cast(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ), + const_cast(mso_sptCalloutSegm1a), sizeof( mso_sptCalloutSegm1a ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault1), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 ) +}; +static const mso_CustomShape msoAccentBorderCallout1 = +{ + const_cast(mso_sptCallout1Vert), SAL_N_ELEMENTS( mso_sptCallout1Vert ), + const_cast(mso_sptCallout1Segm1a), sizeof( mso_sptCallout1Segm1a ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault2), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 ) +}; +static const mso_CustomShape msoAccentBorderCallout2 = +{ + const_cast(mso_sptCallout2Vertb), SAL_N_ELEMENTS( mso_sptCallout2Vertb ), + const_cast(mso_sptCallout2Segm1c), sizeof( mso_sptCallout2Segm1c ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault3), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle2), SAL_N_ELEMENTS( mso_sptCalloutHandle2 ) +}; +static const mso_CustomShape msoAccentBorderCallout3 = +{ + const_cast(mso_sptCallout3Vertb), SAL_N_ELEMENTS( mso_sptCallout3Vertb ), + const_cast(mso_sptCallout3Segm1c), sizeof( mso_sptCallout3Segm1c ) >> 1, + const_cast(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ), + const_cast(mso_sptCalloutDefault4), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCalloutHandle3), SAL_N_ELEMENTS( mso_sptCalloutHandle3 ) +}; + +static const SvxMSDffVertPair mso_sptStraightConnector1Vert[] = +{ + { 0, 0 }, { 21600, 21600 } +}; +static const sal_uInt16 mso_sptStraightConnector1Segm[] = +{ + 0x4000, 0x0001, 0x8000 +}; +static const mso_CustomShape msoStraightConnector1 = +{ + const_cast(mso_sptStraightConnector1Vert), SAL_N_ELEMENTS( mso_sptStraightConnector1Vert ), + const_cast(mso_sptStraightConnector1Segm), sizeof( mso_sptStraightConnector1Segm ) >> 1, + nullptr, 0, + nullptr, + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + nullptr, 0 +}; + +static const SvxMSDffVertPair mso_sptBentConnector2Vert[] = +{ + { 0, 0 }, { 21600, 0 }, { 21600, 21600 } +}; +static const sal_uInt16 mso_sptBentConnector2Segm[] = +{ + 0x4000, 0x0002, 0x8000 +}; +static const mso_CustomShape msoBentConnector2 = +{ + const_cast(mso_sptBentConnector2Vert), SAL_N_ELEMENTS( mso_sptBentConnector2Vert ), + const_cast(mso_sptBentConnector2Segm), sizeof( mso_sptBentConnector2Segm ) >> 1, + nullptr, 0, + nullptr, + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + nullptr, 0 +}; + +static const SvxMSDffVertPair mso_sptBentConnector3Vert[] = +{ + { 0, 0 }, { 0 MSO_I, 0 }, { 0 MSO_I, 21600 }, { 21600, 21600 } +}; +static const sal_uInt16 mso_sptBentConnector3Segm[] = +{ + 0x4000, 0x0003, 0x8000 +}; +static const SvxMSDffCalculationData mso_sptBentConnector3Calc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } } +}; +static const sal_Int32 mso_sptBentConnector3Default[] = +{ + 1, 10800 +}; +static const SvxMSDffHandle mso_sptBentConnector3Handle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 10800, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoBentConnector3 = +{ + const_cast(mso_sptBentConnector3Vert), SAL_N_ELEMENTS( mso_sptBentConnector3Vert ), + const_cast(mso_sptBentConnector3Segm), sizeof( mso_sptBentConnector3Segm ) >> 1, + const_cast(mso_sptBentConnector3Calc), SAL_N_ELEMENTS( mso_sptBentConnector3Calc ), + const_cast(mso_sptBentConnector3Default), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptBentConnector3Handle), SAL_N_ELEMENTS( mso_sptBentConnector3Handle ) +}; + +static const SvxMSDffVertPair mso_sptBentConnector4Vert[] = +{ + { 0, 0 }, { 0 MSO_I, 0 }, { 0 MSO_I, 1 MSO_I }, { 21600, 1 MSO_I }, { 21600, 21600 } +}; +static const sal_uInt16 mso_sptBentConnector4Segm[] = +{ + 0x4000, 0x0004, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptBentConnector4Default[] = +{ + 2, 10800, 10800 +}; +static 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 } +}; +static const mso_CustomShape msoBentConnector4 = +{ + const_cast(mso_sptBentConnector4Vert), SAL_N_ELEMENTS( mso_sptBentConnector4Vert ), + const_cast(mso_sptBentConnector4Segm), sizeof( mso_sptBentConnector4Segm ) >> 1, + const_cast(mso_sptBentConnector4Calc), SAL_N_ELEMENTS( mso_sptBentConnector4Calc ), + const_cast(mso_sptBentConnector4Default), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptBentConnector4Handle), SAL_N_ELEMENTS( mso_sptBentConnector4Handle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptBentConnector5Segm[] = +{ + 0x4000, 0x0005, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptBentConnector5Default[] = +{ + 3, 10800, 10800, 10800 +}; +static 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 } +}; +static const mso_CustomShape msoBentConnector5 = +{ + const_cast(mso_sptBentConnector5Vert), SAL_N_ELEMENTS( mso_sptBentConnector5Vert ), + const_cast(mso_sptBentConnector5Segm), sizeof( mso_sptBentConnector5Segm ) >> 1, + const_cast(mso_sptBentConnector5Calc), SAL_N_ELEMENTS( mso_sptBentConnector5Calc ), + const_cast(mso_sptBentConnector5Default), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptBentConnector5Handle), SAL_N_ELEMENTS( mso_sptBentConnector5Handle ) +}; + +static const SvxMSDffVertPair mso_sptCurvedConnector2Vert[] = +{ + { 0, 0 }, { 10800, 0 }, { 21600, 10800 }, { 21600, 21600 } +}; +static const sal_uInt16 mso_sptCurvedConnector2Segm[] = +{ + 0x4000, 0x2001, 0x8000 +}; +static const mso_CustomShape msoCurvedConnector2 = +{ + const_cast(mso_sptCurvedConnector2Vert), SAL_N_ELEMENTS( mso_sptCurvedConnector2Vert ), + const_cast(mso_sptCurvedConnector2Segm), sizeof( mso_sptCurvedConnector2Segm ) >> 1, + nullptr, 0, + nullptr, + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + nullptr, 0 +}; + +static 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 } +}; +static const sal_uInt16 mso_sptCurvedConnector3Segm[] = +{ + 0x4000, 0x2002, 0x8000 +}; +static const SvxMSDffCalculationData mso_sptCurvedConnector3Calc[] = +{ + { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, + { 0x2001, { 0x400, 1, 2 } }, + { 0x2000, { 0x400, 21600, 0 } }, + { 0x2001, { 0x402, 1, 2 } } +}; +static const sal_Int32 mso_sptCurvedConnector3Default[] = +{ + 1, 10800 +}; +static const SvxMSDffHandle mso_sptCurvedConnector3Handle[] = +{ + { SvxMSDffHandleFlags::RANGE, + 0x100, 10800, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff } +}; +static const mso_CustomShape msoCurvedConnector3 = +{ + const_cast(mso_sptCurvedConnector3Vert), SAL_N_ELEMENTS( mso_sptCurvedConnector3Vert ), + const_cast(mso_sptCurvedConnector3Segm), sizeof( mso_sptCurvedConnector3Segm ) >> 1, + const_cast(mso_sptCurvedConnector3Calc), SAL_N_ELEMENTS( mso_sptCurvedConnector3Calc ), + const_cast(mso_sptCurvedConnector3Default), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCurvedConnector3Handle), SAL_N_ELEMENTS( mso_sptCurvedConnector3Handle ) +}; + +static 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 } + +}; +static const sal_uInt16 mso_sptCurvedConnector4Segm[] = +{ + 0x4000, 0x2003, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptCurvedConnector4Default[] = +{ + 2, 10800, 10800 +}; +static 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 } +}; +static const mso_CustomShape msoCurvedConnector4 = +{ + const_cast(mso_sptCurvedConnector4Vert), SAL_N_ELEMENTS( mso_sptCurvedConnector4Vert ), + const_cast(mso_sptCurvedConnector4Segm), sizeof( mso_sptCurvedConnector4Segm ) >> 1, + const_cast(mso_sptCurvedConnector4Calc), SAL_N_ELEMENTS( mso_sptCurvedConnector4Calc ), + const_cast(mso_sptCurvedConnector4Default), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCurvedConnector4Handle), SAL_N_ELEMENTS( mso_sptCurvedConnector4Handle ) +}; + +static 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 } +}; +static const sal_uInt16 mso_sptCurvedConnector5Segm[] = +{ + 0x4000, 0x2004, 0x8000 +}; +static 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 } } +}; +static const sal_Int32 mso_sptCurvedConnector5Default[] = +{ + 3, 10800, 10800, 10800 +}; +static 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 } +}; +static const mso_CustomShape msoCurvedConnector5 = +{ + const_cast(mso_sptCurvedConnector5Vert), SAL_N_ELEMENTS( mso_sptCurvedConnector5Vert ), + const_cast(mso_sptCurvedConnector5Segm), sizeof( mso_sptCurvedConnector5Segm ) >> 1, + const_cast(mso_sptCurvedConnector5Calc), SAL_N_ELEMENTS( mso_sptCurvedConnector5Calc ), + const_cast(mso_sptCurvedConnector5Default), + nullptr, 0, + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(mso_sptCurvedConnector5Handle), SAL_N_ELEMENTS( mso_sptCurvedConnector5Handle ) +}; + +/////////////////////////////teardrop +static 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 +static 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 +static const sal_uInt16 mso_sptTearDropSegm[] = +{ + 0x4000, 0xa701, 0xa801, 0xa701, 0x2002, 0x6000, 0x8000 +}; + +static const SvxMSDffTextRectangles mso_sptTearDropTextRect[] = +{ + { { 2863, 2863 }, { 18737, 18737 } } +}; + +//the range of adjust values +static 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 +static const sal_Int32 mso_sptTearDropDefault[] = +{ + 1, 21600 +}; + +static const mso_CustomShape msoTearDrop = +{ + const_cast(mso_sptTearDropVert), SAL_N_ELEMENTS( mso_sptTearDropVert ), + const_cast(mso_sptTearDropSegm), sizeof( mso_sptTearDropSegm ) >> 1, + const_cast(mso_sptTearDropCalc), SAL_N_ELEMENTS(mso_sptTearDropCalc), + const_cast(mso_sptTearDropDefault), + const_cast(mso_sptTearDropTextRect), SAL_N_ELEMENTS( mso_sptTearDropTextRect ), + 21600, 21600, + MIN_INT32, MIN_INT32, + nullptr, 0, + const_cast(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..ee7143459 --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShapeHandle.cxx @@ -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 . + */ + +#include "EnhancedCustomShapeHandle.hxx" +#include +#include +#include + + +EnhancedCustomShapeHandle::EnhancedCustomShapeHandle( css::uno::Reference< css::drawing::XShape > const & xCustomShape, sal_uInt32 nIndex ) : + mnIndex ( nIndex ), + mxCustomShape ( xCustomShape ) +{ +} + + +EnhancedCustomShapeHandle::~EnhancedCustomShapeHandle() +{ +} + + +void SAL_CALL EnhancedCustomShapeHandle::acquire() throw() +{ + OWeakObject::acquire(); +} + + +void SAL_CALL EnhancedCustomShapeHandle::release() throw() +{ + OWeakObject::release(); +} + +// XCustomShapeHandle +css::awt::Point SAL_CALL EnhancedCustomShapeHandle::getPosition() +{ + const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape* >(GetSdrObjectFromXShape(mxCustomShape))); + + if(!bIsSdrObjCustomShape) + { + throw css::uno::RuntimeException(); + } + + SdrObjCustomShape& rSdrObjCustomShape(static_cast< SdrObjCustomShape& >(*GetSdrObjectFromXShape(mxCustomShape))); + Point aPosition; + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + + 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 ) +{ + const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape* >(GetSdrObjectFromXShape(mxCustomShape))); + + if(!bIsSdrObjCustomShape) + { + throw css::uno::RuntimeException(); + } + + SdrObjCustomShape& rSdrObjCustomShape(static_cast< SdrObjCustomShape& >(*GetSdrObjectFromXShape(mxCustomShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + + 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..0fa64bbe4 --- /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 +#include +#include +#include +#include + +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() throw() override; + virtual void SAL_CALL release() throw() 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..d97a73a7c --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShapeTypeNames.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 +#include +#include +#include + +typedef std::unordered_map< const char*, MSO_SPT, rtl::CStringHash, rtl::CStringEqual> TypeNameHashMap; + +static TypeNameHashMap* pHashMap = nullptr; +static ::osl::Mutex& getHashMapMutex() +{ + static osl::Mutex s_aHashMapProtection; + return s_aHashMapProtection; +} + +namespace { + +struct NameTypeTable +{ + const char* pS; + MSO_SPT pE; +}; + +} + +static 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 + +MSO_SPT EnhancedCustomShapeTypeNames::Get( const OUString& rShapeType ) +{ + if ( !pHashMap ) + { // init hash map + ::osl::MutexGuard aGuard( getHashMapMutex() ); + if ( !pHashMap ) + { + TypeNameHashMap* pH = new TypeNameHashMap; + const NameTypeTable* pPtr = pNameTypeTableArray; + const NameTypeTable* pEnd = pPtr + SAL_N_ELEMENTS( pNameTypeTableArray ); + for ( ; pPtr < pEnd; pPtr++ ) + (*pH)[ pPtr->pS ] = pPtr->pE; + pHashMap = pH; + } + } + MSO_SPT eRetValue = mso_sptNil; + int i, nLen = rShapeType.getLength(); + std::unique_ptr pBuf(new char[ nLen + 1 ]); + for ( i = 0; i < nLen; i++ ) + pBuf[ i ] = static_cast(rShapeType[ i ]); + pBuf[ i ] = 0; + TypeNameHashMap::const_iterator aHashIter( pHashMap->find( pBuf.get() ) ); + if ( aHashIter != pHashMap->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(); +} + +typedef std::unordered_map< const char*, const char*, rtl::CStringHash, rtl::CStringEqual> TypeACCNameHashMap; + +static TypeACCNameHashMap* pACCHashMap = nullptr; + +namespace { + +struct ACCNameTypeTable +{ + const char* pS; + const char* pE; +}; + +} + +static 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" } +}; + +OUString EnhancedCustomShapeTypeNames::GetAccName( const OUString& rShapeType ) +{ + if ( !pACCHashMap ) + { // init hash map + ::osl::MutexGuard aGuard( getHashMapMutex() ); + if ( !pACCHashMap ) + { + TypeACCNameHashMap* pH = new TypeACCNameHashMap; + const ACCNameTypeTable* pPtr = pACCNameTypeTableArray; + const ACCNameTypeTable* pEnd = pPtr + SAL_N_ELEMENTS( pACCNameTypeTableArray ); + for ( ; pPtr < pEnd; pPtr++ ) + (*pH)[ pPtr->pS ] = pPtr->pE; + pACCHashMap = pH; + } + } + OUString sRetValue; + int i, nLen = rShapeType.getLength(); + std::unique_ptr pBuf(new char[ nLen + 1 ]); + for ( i = 0; i < nLen; i++ ) + pBuf[ i ] = static_cast(rShapeType[ i ]); + pBuf[ i ] = 0; + TypeACCNameHashMap::const_iterator aHashIter( pACCHashMap->find( pBuf.get() ) ); + if ( aHashIter != pACCHashMap->end() ) + sRetValue = OUString::createFromAscii( (*aHashIter).second ); + return sRetValue; +} + +/* 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..4032e62f8 --- /dev/null +++ b/svx/source/dialog/AccessibilityCheckDialog.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/. + * + */ + +#include + +#include +#include + +namespace svx +{ +AccessibilityCheckEntry::AccessibilityCheckEntry( + weld::Container* pParent, std::shared_ptr 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")) +{ +} + +AccessibilityCheckDialog::~AccessibilityCheckDialog() {} + +short AccessibilityCheckDialog::run() +{ + sal_Int32 i = 0; + + for (std::shared_ptr const& pIssue : m_aIssueCollection.getIssues()) + { + auto xEntry + = std::make_unique(m_xAccessibilityCheckBox.get(), pIssue); + m_xAccessibilityCheckBox->reorder_child(xEntry->get_widget(), i++); + m_aAccessibilityCheckEntries.push_back(std::move(xEntry)); + } + return GenericDialogController::run(); +} + +} // 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..d5561ec5b --- /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 +#include +#include + +#include +#include +#include + +using namespace css; + +namespace svx::classification +{ +OUString convertClassificationResultToString(std::vector 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 const& rxPropertyContainer, + OUString const& rName) +{ + try + { + uno::Reference xPropertySet(rxPropertyContainer, uno::UNO_QUERY); + return xPropertySet->getPropertyValue(rName).get(); + } + catch (const css::uno::Exception&) + { + } + + return OUString(); +} + +bool containsProperty(uno::Sequence const& rProperties, OUString const& rName) +{ + return std::any_of(rProperties.begin(), rProperties.end(), + [&](const beans::Property& rProperty) { return rProperty.Name == rName; }); +} + +void removeAllProperties(uno::Reference const& rxPropertyContainer) +{ + uno::Reference xPropertySet(rxPropertyContainer, uno::UNO_QUERY); + const uno::Sequence aProperties + = xPropertySet->getPropertySetInfo()->getProperties(); + + for (const beans::Property& rProperty : aProperties) + { + rxPropertyContainer->removeProperty(rProperty.Name); + } +} + +bool addOrInsertDocumentProperty( + uno::Reference const& rxPropertyContainer, OUString const& rsKey, + OUString const& rsValue) +{ + uno::Reference xPropertySet(rxPropertyContainer, uno::UNO_QUERY); + + try + { + if (containsProperty(xPropertySet->getPropertySetInfo()->getProperties(), rsKey)) + xPropertySet->setPropertyValue(rsKey, uno::makeAny(rsValue)); + else + rxPropertyContainer->addProperty(rsKey, beans::PropertyAttribute::REMOVABLE, + uno::makeAny(rsValue)); + } + catch (const uno::Exception& /*rException*/) + { + return false; + } + return true; +} + +void insertFullTextualRepresentationAsDocumentProperty( + uno::Reference const& rxPropertyContainer, + sfx::ClassificationKeyCreator const& rKeyCreator, + std::vector const& rResults) +{ + OUString sString = convertClassificationResultToString(rResults); + addOrInsertDocumentProperty(rxPropertyContainer, rKeyCreator.makeFullTextualRepresentationKey(), + sString); +} + +void insertCreationOrigin(uno::Reference 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..25144cc8e --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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; + break; + } + } + + return false; +} + +namespace { + +constexpr size_t RECENTLY_USED_LIMIT = 5; + +const OUString constRecentlyUsedFileName("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(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(OString const & 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 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 bool bPerParagraph, const std::function& rParagraphSignHandler) + : GenericDialogController(pParent, "svx/ui/classificationdialog.ui", "AdvancedDocumentClassificationDialog") + , maHelper(SfxObjectShell::Current()->getDocProperties()) + , maInternationalHelper(SfxObjectShell::Current()->getDocProperties(), /*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 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 const & rInput) +{ + m_aInitialValues = 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") + { + aWalker.children(); + while (aWalker.isValid()) + { + if (aWalker.name() == "elementGroup") + { + std::vector 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 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 const & rResultCollection : m_aRecentlyUsedValuesCollection) + { + aXmlWriter.startElement("elementGroup"); + + writeResultToXml(aXmlWriter, rResultCollection); + + aXmlWriter.endElement(); + } + + aXmlWriter.endElement(); + + aXmlWriter.endDocument(); +} + +void ClassificationDialog::readIn(std::vector 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(); + std::unique_ptr pSet(new SfxItemSet(rEdEngine.GetParaAttribs(nParagraph))); + pSet->Put(SvxWeightItem(eWeight, EE_CHAR_WEIGHT)); + rEdEngine.SetParaAttribs(nParagraph, *pSet); + } + 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(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 ClassificationDialog::getResult() +{ + std::vector aClassificationResults; + + ClassificationEditEngine& rEdEngine = m_xEditWindow->getEditEngine(); + std::unique_ptr pEditText(rEdEngine.CreateTextObject()); + + sal_Int32 nCurrentParagraph = -1; + + std::vector 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(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(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 pEditText(m_xEditWindow->getEditEngine().CreateTextObject()); + std::vector 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(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::ToggleButton&, void) +{ + m_xEditWindow->InvertSelectionWeight(); +} + +IMPL_LINK_NOARG(ClassificationDialog, EditWindowModifiedHdl, LinkParamNone*, void) +{ + toggleWidgetsDependingOnCategory(); +} + +IMPL_STATIC_LINK(ClassificationDialog, ExpandedHdl, weld::Expander&, rExpander, void) +{ + std::shared_ptr 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..4dd5c337e --- /dev/null +++ b/svx/source/dialog/ClassificationEditView.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 + +#include +#include +#include + +#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& /*rTxtColor*/, std::optional& /*rFldColor*/) +{ + OUString aString; + const ClassificationField* pClassificationField = dynamic_cast(rField.GetField()); + if (pClassificationField) + aString = pClassificationField->msDescription; + else + aString = "Unknown"; + return aString; +} + +ClassificationEditView::ClassificationEditView() +{ +} + +void ClassificationEditView::makeEditEngine() +{ + m_xEditEngine.reset(new ClassificationEditEngine(EditEngine::CreatePool())); +} + +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; + + std::unique_ptr pSet(new SfxItemSet(m_xEditEngine->GetParaAttribs(nParagraph))); + if (const SfxPoolItem* pItem = pSet->GetItem(EE_CHAR_WEIGHT, false)) + { + const SvxWeightItem* pWeightItem = dynamic_cast(pItem); + if (pWeightItem && pWeightItem->GetWeight() == WEIGHT_BOLD) + eFontWeight = WEIGHT_NORMAL; + } + SvxWeightItem aWeight(eFontWeight, EE_CHAR_WEIGHT); + pSet->Put(aWeight); + m_xEditEngine->SetParaAttribs(nParagraph, *pSet); + } + + 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..96adf83ab --- /dev/null +++ b/svx/source/dialog/ClassificationEditView.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/. + * + */ + +#ifndef INCLUDED_SVX_CLASSIFICATIONEDITVIEW_HXX +#define INCLUDED_SVX_CLASSIFICATIONEDITVIEW_HXX + +#include +#include +#include +#include +#include + +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& rTxtColor, std::optional& 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(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/SafeModeDialog.cxx b/svx/source/dialog/SafeModeDialog.cxx new file mode 100644 index 000000000..b74d2a93d --- /dev/null +++ b/svx/source/dialog/SafeModeDialog.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/. + */ + +#include "SafeModeDialog.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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")) + , maBackupFileHelper() +{ + m_xDialog->set_centered_on_parent(false); + mxRadioRestore->connect_clicked(LINK(this, SafeModeDialog, RadioBtnHdl)); + mxRadioConfigure->connect_clicked(LINK(this, SafeModeDialog, RadioBtnHdl)); + mxRadioExtensions->connect_clicked(LINK(this, SafeModeDialog, RadioBtnHdl)); + mxRadioReset->connect_clicked(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::Button&, rBtn, void) +{ + if (&rBtn == mxRadioRestore.get()) + { + // 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 (&rBtn == mxRadioConfigure.get()) + { + // 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 (&rBtn == mxRadioExtensions.get()) + { + // 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 (&rBtn == mxRadioReset.get()) + { + // 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(); + } +} + +namespace { + class ProfileExportedDialog : public weld::GenericDialogController + { + private: + std::unique_ptr m_xButton; + + DECL_LINK(OpenHdl, weld::Button&, void); + public: + explicit ProfileExportedDialog(weld::Window* pParent); + }; + + ProfileExportedDialog::ProfileExportedDialog(weld::Window* pParent) + : GenericDialogController(pParent, "svx/ui/profileexporteddialog.ui", "ProfileExportedDialog") + , m_xButton(m_xBuilder->weld_button("ok")) + { + m_xButton->connect_clicked(LINK(this, ProfileExportedDialog, OpenHdl)); + } + + IMPL_LINK_NOARG(ProfileExportedDialog, 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); + } +} + +IMPL_LINK(SafeModeDialog, CreateZipBtnHdl, weld::Button&, /*rBtn*/, void) +{ + const OUString zipFileName("libreoffice-profile.zip"); + const OUString zipFileURL(comphelper::BackupFileHelper::getUserProfileURL() + "/" + zipFileName); + 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 xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + SvxResId(RID_SVXSTR_SAFEMODE_ZIP_FAILURE))); + xBox->run(); + return; + } + + ProfileExportedDialog aDialog(m_xDialog.get()); + aDialog.run(); +} + +IMPL_LINK(SafeModeDialog, CheckBoxHdl, weld::ToggleButton&, /*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..daba66caf --- /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 +#include + +class SafeModeDialog : public weld::GenericDialogController +{ +public: + explicit SafeModeDialog(weld::Window* pParent); + virtual short run() override; + virtual ~SafeModeDialog() override; + +private: + std::unique_ptr mxBtnContinue; + std::unique_ptr mxBtnRestart; + std::unique_ptr mxBtnApply; + + std::unique_ptr mxBoxRestore; + std::unique_ptr mxBoxConfigure; + std::unique_ptr mxBoxDeinstall; + std::unique_ptr mxBoxReset; + + std::unique_ptr mxRadioRestore; + std::unique_ptr mxRadioConfigure; + std::unique_ptr mxRadioExtensions; + std::unique_ptr mxRadioReset; + + std::unique_ptr mxCBCheckProfilesafeConfig; + std::unique_ptr mxCBCheckProfilesafeExtensions; + std::unique_ptr mxCBDisableAllExtensions; + std::unique_ptr mxCBDeinstallUserExtensions; + std::unique_ptr mxCBResetSharedExtensions; + std::unique_ptr mxCBResetBundledExtensions; + std::unique_ptr mxCBDisableHWAcceleration; + std::unique_ptr mxCBResetCustomizations; + std::unique_ptr mxCBResetWholeUserProfile; + + std::unique_ptr mxBugLink; + std::unique_ptr mxUserProfileLink; + std::unique_ptr mxBtnCreateZip; + std::unique_ptr mxExpander; + + // local BackupFileHelper for handling possible restores + comphelper::BackupFileHelper maBackupFileHelper; + + void enableDisableWidgets(); + void applyChanges(); + + DECL_LINK(RadioBtnHdl, weld::Button&, void); + DECL_LINK(CheckBoxHdl, weld::ToggleButton&, 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..541057e0c --- /dev/null +++ b/svx/source/dialog/SafeModeUI.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 +#include +#include + +#include + +#include +#include + +#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; + vcl::Window* pParentWindow = Application::GetDefDialogParent(); + SafeModeDialog aDialog(pParentWindow ? pParentWindow->GetFrameWeld() : nullptr); + 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 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 + +#include +#include + +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..5eb062b17 --- /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 +#include +#include +#include +#include + +using namespace css; +using namespace css::uno; +using namespace css::text; +using namespace css::style; + +Reference SvxNumOptionsTabPageHelper::GetNumberingProvider() +{ + Reference xContext( ::comphelper::getProcessComponentContext() ); + Reference xRet = text::DefaultNumberingProvider::create(xContext); + return xRet; +} + +void SvxNumOptionsTabPageHelper::GetI18nNumbering(weld::ComboBox& rFmtLB, sal_uInt16 nDoNotRemove) +{ + Reference xDefNum = GetNumberingProvider(); + Reference 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 NumberingType::CHARS_LOWER_LETTER_N && nEntryData != nDoNotRemove) + aRemove[i] = nEntryData; + } + if(xInfo.is()) + { + Sequence 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(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..05957ba37 --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 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 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::ToggleButton&, void); + DECL_LINK( CbxTransHdl, weld::ToggleButton&, 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::ToggleButton&, 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() ) + { + 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::ToggleButton&, 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(PushFlags::LINECOLOR | 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::StateChanged( sal_uInt16 nSID, SfxItemState /*eState*/, + const SfxPoolItem* pItem ) +{ + if ( ( nSID == SID_BMPMASK_EXEC ) && pItem ) + { + const SfxBoolItem* pStateItem = dynamic_cast( 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 pDlg = VclPtr::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"), 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"), 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"), 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"), GetFrameWeld())) + , m_xCbxTrans(m_xBuilder->weld_check_button("cbx5")) + , m_xLbColorTrans(new ColorListBox(m_xBuilder->weld_menu_button("color5"), 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( 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(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(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(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(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.IsTransparent() ) + aMask.CombineSimple( rBitmapEx.GetMask(), BmpCombine::Or ); + + 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; + long nR; + long nG; + long nB; + std::unique_ptr pMinR(new long[nCount]); + std::unique_ptr pMaxR(new long[nCount]); + std::unique_ptr pMinG(new long[nCount]); + std::unique_ptr pMaxG(new long[nCount]); + std::unique_ptr pMinB(new long[nCount]); + std::unique_ptr pMaxB(new long[nCount]); + sal_uInt16 i; + + aMtf.SetPrefSize( rMtf.GetPrefSize() ); + aMtf.SetPrefMapMode( rMtf.GetPrefMapMode() ); + + // Prepare Color comparison array + for( i = 0; i < nCount; i++ ) + { + long nTol = ( pTols[i] * 255 ) / 100; + + long nVal = static_cast(pSrcCols[i].GetRed()); + pMinR[i] = std::max( nVal - nTol, 0L ); + pMaxR[i] = std::min( nVal + nTol, 255L ); + + nVal = static_cast(pSrcCols[i].GetGreen()); + pMinG[i] = std::max( nVal - nTol, 0L ); + pMaxG[i] = std::min( nVal + nTol, 255L ); + + nVal = static_cast(pSrcCols[i].GetBlue()); + pMinB[i] = std::max( nVal - nTol, 0L ); + pMaxB[i] = std::min( nVal + nTol, 255L ); + + 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(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(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(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(pAction); + + aCol = pAct->GetColor(); + TEST_COLS(); + + if( bReplace ) + pAct = new MetaTextColorAction( aCol ); + + aMtf.AddAction( pAct ); + } + break; + + case MetaActionType::TEXTFILLCOLOR: + { + MetaTextFillColorAction* pAct = static_cast(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(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(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(pAction); + const Bitmap aBmp( Mask( pAct->GetBitmap() ).GetBitmapEx().GetBitmap() ); + + pAct = new MetaBmpAction( pAct->GetPoint(), aBmp ); + aMtf.AddAction( pAct ); + } + break; + + case MetaActionType::BMPSCALE: + { + MetaBmpScaleAction* pAct = static_cast(pAction); + const Bitmap aBmp( Mask( pAct->GetBitmap() ).GetBitmapEx().GetBitmap() ); + + pAct = new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(), aBmp ); + aMtf.AddAction( pAct ); + } + break; + + case MetaActionType::BMPSCALEPART: + { + MetaBmpScalePartAction* pAct = static_cast(pAction); + const Bitmap aBmp( Mask( 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(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(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(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.GetMask() ) ); + 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..d82004f47 --- /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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "contimp.hxx" +#include "contwnd.hxx" +#include +#include +#include +#include +#include "dlgunit.hxx" +#include + +SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(SvxContourDlgChildWindow, SID_CONTOUR_DLG); + +SvxContourDlgItem::SvxContourDlgItem( SvxSuperContourDlg& rContourDlg, SfxBindings& rBindings ) : + SfxControllerItem ( SID_CONTOUR_EXEC, rBindings ), + rDlg ( rContourDlg ) +{ +} + +void SvxContourDlgItem::StateChanged( sal_uInt16 nSID, SfxItemState /*eState*/, const SfxPoolItem* pItem ) +{ + if ( pItem && ( SID_CONTOUR_EXEC == nSID ) ) + { + const SfxBoolItem* pStateItem = dynamic_cast( 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(pBindings, this, _pParent->GetFrameWeld())); + SvxContourDlg* pDlg = static_cast(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(*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().GetMask(); + 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(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() ); + 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 xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querysavecontchangesdialog.ui")); + std::unique_ptr 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 xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querydeletecontourdialog.ui")); + std::unique_ptr 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( OBJ_RECT ); + } + else if (rId == "TBI_CIRCLE") + { + SetActiveTool(rId); + m_xContourWnd->SetObjKind( OBJ_CIRC ); + } + else if (rId == "TBI_POLY") + { + SetActiveTool(rId); + m_xContourWnd->SetObjKind( OBJ_POLY ); + } + 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 xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/queryunlinkgraphicsdialog.ui")); + std::unique_ptr 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(const OString& 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(const OString& 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( 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 long nTol = static_cast(m_xMtfTolerance->get_value(FieldUnit::PERCENT) * 255 / 100); + + Bitmap aMask = aGraphic.GetBitmapEx().GetBitmap().CreateMask( rColor, nTol ); + + if( aGraphic.IsTransparent() ) + aMask.CombineSimple( aGraphic.GetBitmapEx().GetMask(), BmpCombine::Or ); + + if( !!aMask ) + { + std::unique_ptr xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querynewcontourdialog.ui")); + std::unique_ptr 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..c43cafb9e --- /dev/null +++ b/svx/source/dialog/charmap.cxx @@ -0,0 +1,1872 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include + + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 pScrolledWindow, const VclPtr& rVirDev) + : mxVirDev(rVirDev) + , mxScrollArea(std::move(pScrolledWindow)) + , mxContext(comphelper::getProcessComponentContext()) + , nX(0) + , nY(0) + , maFontSize(0, 0) + , maPosition(0,0) + , mbRecalculateFont(true) + , mbUpdateForeground(true) + , mbUpdateBackground(true) +{ + init(); + + mxScrollArea->set_user_managed_scrolling(); +} + +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_vscroll_width() + 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()).IsInside(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 xBuilder(Application::CreateBuilder(GetDrawingArea(), "svx/ui/charsetmenu.ui")); + std::unique_ptr 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(const OString& 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 xClipboard = + css::datatransfer::clipboard::SystemClipboard::create(comphelper::getProcessComponentContext()); + + if (xClipboard.is()) + { + TETextDataObject* pDataObj = new TETextDataObject(rOUStr); + + try + { + xClipboard->setContents( pDataObj, nullptr ); + + css::uno::Reference 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()); + css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size()); + + for (size_t i = 0; i < maFavCharList.size(); ++i) + { + aFavCharList[i] = maFavCharList[i]; + aFavCharFontList[i] = maFavCharFontList[i]; + } + + std::shared_ptr batch(comphelper::ConfigurationChanges::create(mxContext)); + 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()); + css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size()); + + for (size_t i = 0; i < maFavCharList.size(); ++i) + { + aFavCharList[i] = maFavCharList[i]; + aFavCharFontList[i] = maFavCharFontList[i]; + } + + std::shared_ptr batch(comphelper::ConfigurationChanges::create(mxContext)); + 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(); + return (nBase + ((point.X() - m_nXGap)/nX) + ((point.Y() - m_nYGap)/nY) * 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 its at the edge to fill unused space +tools::Rectangle SvxShowCharSet::getGridRectangle(const Point &rPointUL, const Size &rOutputSize) +{ + long x = rPointUL.X() - 1; + long y = rPointUL.Y() - 1; + Point aPointUL(x+1, y+1); + Size aGridSize(nX-1, nY-1); + + long nXDistFromLeft = x - m_nXGap; + if (nXDistFromLeft <= 1) + { + aPointUL.setX( 1 ); + aGridSize.AdjustWidth(m_nXGap + nXDistFromLeft ); + } + long nXDistFromRight = rOutputSize.Width() - m_nXGap - nX - x; + if (nXDistFromRight <= 1) + aGridSize.AdjustWidth(m_nXGap + nXDistFromRight ); + + long nXDistFromTop = y - m_nYGap; + if (nXDistFromTop <= 1) + { + aPointUL.setY( 1 ); + aGridSize.AdjustHeight(m_nYGap + nXDistFromTop ); + } + 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()); + + int i; + 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)); + } + 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 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 ); + } + + 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( 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 ); + } + } + 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( 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 ); + } + } + SelectIndex( (LastInView() - COLUMN_COUNT + 1) + (nSelectedIndex % COLUMN_COUNT) ); + } + + Invalidate(); +} + +SvxShowCharSet::~SvxShowCharSet() +{ + if (m_xAccessible.is()) + { + m_aItems.clear(); + m_xAccessible->clearCharSetControl(); + m_xAccessible.clear(); + } +} + +css::uno::Reference< XAccessible > SvxShowCharSet::CreateAccessible() +{ + OSL_ENSURE(!m_xAccessible.is(),"Accessible already created!"); + m_xAccessible = new svx::SvxShowCharSetAcc(this); + return m_xAccessible.get(); +} + +svx::SvxShowCharSetItem* SvxShowCharSet::ImplGetItem( int _nPos ) +{ + ItemsMap::iterator aFind = m_aItems.find(_nPos); + if ( aFind == m_aItems.end() ) + { + OSL_ENSURE(m_xAccessible.is(), "Who wants to create a child of my table without a parent?"); + auto xItem = std::make_shared(*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 ⊂ + 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(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; +#if (U_ICU_VERSION_MAJOR_NUM > 4) || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM >= 4) + 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; +#endif +#if (U_ICU_VERSION_MAJOR_NUM > 4) || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM >= 6) + 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; +#endif +// 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, 0x18D8F, SvxResId(RID_SUBSETSTR_TANGUT_SUPPLEMENT) ); + break; + case UBLOCK_YEZIDI: + aAllSubsets.emplace_back( 0x10E80, 0x10EBF, SvxResId(RID_SUBSETSTR_YEZIDI) ); + 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..14b4c809f --- /dev/null +++ b/svx/source/dialog/compressgraphicdialog.cxx @@ -0,0 +1,432 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(); +} + +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(); +} + +CompressGraphicsDialog::~CompressGraphicsDialog() +{ +} + +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_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); + + UpdateNewWidthMF(); + UpdateNewHeightMF(); + UpdateResolutionLB(); + Update(); +} + +void CompressGraphicsDialog::Update() +{ + GfxLinkType aLinkType = m_aGraphic.GetGfxLink().GetType(); + OUString aGraphicTypeString; + switch(aLinkType) + { + 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; + default: + aGraphicTypeString = SvxResId(STR_IMAGE_UNKNOWN); + break; + } + m_xLabelGraphicType->set_label(aGraphicTypeString); + + const FieldUnit eFieldUnit = m_rBindings.GetDispatcher()->GetModule()->GetFieldUnit(); + const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() ); + sal_Unicode cSeparator = rLocaleWrapper.getNumDecimalSep()[0]; + + ScopedVclPtrInstance 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(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); + + SvMemoryStream aMemStream; + aMemStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + m_aGraphic.ExportNative(aMemStream); + sal_Int32 aNativeSize = aMemStream.TellEnd(); + + OUString aNativeSizeString = SvxResId(STR_IMAGE_CAPACITY); + aNativeSizeString = aNativeSizeString.replaceAll("$(CAPACITY)", OUString::number(aNativeSize / 1024)); + m_xFixedText5->set_label(aNativeSizeString); + + m_xFixedText6->set_label("??"); +} + +void CompressGraphicsDialog::UpdateNewWidthMF() +{ + int nPixelX = static_cast( GetViewWidthInch() * m_dResolution ); + m_xMFNewWidth->set_value(nPixelX); +} + +void CompressGraphicsDialog::UpdateNewHeightMF() +{ + int nPixelY = static_cast( GetViewHeightInch() * m_dResolution ); + m_xMFNewHeight->set_value(nPixelY); +} + +void CompressGraphicsDialog::UpdateResolutionLB() +{ + m_xResolutionLB->set_entry_text( OUString::number( static_cast(m_dResolution) ) ); +} + +double CompressGraphicsDialog::GetViewWidthInch() const +{ + return static_cast(vcl::ConvertValue(m_aViewSize100mm.Width(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0; +} + +double CompressGraphicsDialog::GetViewHeightInch() const +{ + return static_cast(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() ) + { + long nPixelX = static_cast( GetViewWidthInch() * m_dResolution ); + long nPixelY = static_cast( GetViewHeightInch() * m_dResolution ); + + aBitmap.Scale( Size( nPixelX, nPixelY ), GetSelectedInterpolationType() ); + } + Graphic aScaledGraphic( aBitmap ); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + + Sequence< PropertyValue > aFilterData( 3 ); + aFilterData[ 0 ].Name = "Interlaced"; + aFilterData[ 0 ].Value <<= sal_Int32(0); + aFilterData[ 1 ].Name = "Compression"; + aFilterData[ 1 ].Value <<= static_cast(m_xCompressionMF->get_value()); + aFilterData[ 2 ].Name = "Quality"; + aFilterData[ 2 ].Value <<= static_cast(m_xQualityMF->get_value()); + + OUString aGraphicFormatName = m_xLosslessRB->get_active() ? OUString( "png" ) : OUString( "jpg" ); + + sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( aGraphicFormatName ); + rFilter.ExportGraphic( aScaledGraphic, "none", aStream, nFilterFormat, &aFilterData ); +} + +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(m_xResolutionLB->get_active_text().toInt32()); + + UpdateNewWidthMF(); + UpdateNewHeightMF(); + Update(); +} + +IMPL_LINK_NOARG( CompressGraphicsDialog, ToggleCompressionRB, weld::ToggleButton&, 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::ToggleButton&, 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 aNewSizeString = SvxResId(STR_IMAGE_CAPACITY); + aNewSizeString = aNewSizeString.replaceAll("$(CAPACITY)", aSizeAsString); + m_xFixedText6->set_label(aNewSizeString); + } +} + +tools::Rectangle CompressGraphicsDialog::GetScaledCropRectangle() const +{ + if ( m_xReduceResolutionCB->get_active() ) + { + long nPixelX = static_cast( GetViewWidthInch() * m_dResolution ); + long nPixelY = static_cast( GetViewHeightInch() * m_dResolution ); + Size aSize = m_aGraphic.GetBitmapEx().GetSizePixel(); + double aScaleX = nPixelX / static_cast(aSize.Width()); + double aScaleY = nPixelY / static_cast(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, OUString("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..b3006fe24 --- /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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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( !pSdrPage ) + return; + + SetMapMode(MapMode(MapUnit::Map100thMM)); + + OutputDevice* pOD = pView->GetFirstOutputDevice(); // GetWin( 0 ); + tools::Rectangle aRect = pSdrPage->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 long nWidth = aWinSize.Width(); + const long nHeight = aWinSize.Height(); + if (aRect.GetHeight() == 0) + return; + double fRectWH = static_cast(aRect.GetWidth()) / aRect.GetHeight(); + if (nHeight == 0) + return; + double fWinWH = static_cast(nWidth) / nHeight; + + // Adapt bitmap to Thumb size (not here!) + if ( fRectWH < fWinWH) + { + aNewSize.setWidth( static_cast( static_cast(nHeight) * fRectWH ) ); + aNewSize.setHeight( nHeight ); + } + else + { + aNewSize.setWidth( nWidth ); + aNewSize.setHeight( static_cast( static_cast(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.TopLeft().X(), aRect.TopLeft().Y() ); + 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(); + sal_uInt16 nId = pObj->GetObjIdentifier(); + if( nInv == SdrInventor::Default && nId == OBJ_EDGE ) + { + bFound = true; + + // potential memory leak here (!). Create SdrObjList only when there is + // not yet one. + if(!pSdrPage) + { + pSdrPage.reset( new SdrPage( + pView->getSdrModelFromSdrView(), + false) ); + } + + const SdrEdgeObj* pTmpEdgeObj = static_cast(pObj); + pEdgeObj = pTmpEdgeObj->CloneSdrObject(pSdrPage->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(pSdrPage->getSdrModelFromSdrPage()); + pSdrPage->InsertObject( pObj1 ); + pEdgeObj->ConnectToNode( true, pObj1 ); + } + + if( pTmpObj2 ) + { + SdrObject* pObj2 = pTmpObj2->CloneSdrObject(pSdrPage->getSdrModelFromSdrPage()); + pSdrPage->InsertObject( pObj2 ); + pEdgeObj->ConnectToNode( false, pObj2 ); + } + + pSdrPage->InsertObject( pEdgeObj ); + } + } + } + + if( !pEdgeObj ) + { + pEdgeObj = new SdrEdgeObj(pView->getSdrModelFromSdrView()); + } + + AdaptSize(); +} + +void SvxXConnectionPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + rRenderContext.Push(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 (pSdrPage) + { + // 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 < pSdrPage->GetObjCount(); ++a) + { + SdrObject* pObject = pSdrPage->GetObj(a); + DBG_ASSERT(pObject, + "SvxXConnectionPreview::Paint: Corrupt ObjectList (!)"); + aObjectVector.push_back(pObject); + } + + sdr::contact::ObjectContactOfObjListPainter aPainter(rRenderContext, 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 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(aXFrac) > 0.001 && static_cast(aXFrac) < 1000.0 && + static_cast(aYFrac) > 0.001 && static_cast(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() ); + long nX = static_cast( ( static_cast(aOutSize.Width()) - ( static_cast(aOutSize.Width()) * static_cast(*pMultFrac) ) ) / 2.0 + 0.5 ); + long nY = static_cast( ( static_cast(aOutSize.Height()) - ( static_cast(aOutSize.Height()) * static_cast(*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..c8b59cb72 --- /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 +#include "contwnd.hxx" +#include + +class SvxSuperContourDlg; + +class SvxContourDlgItem : public SfxControllerItem +{ + SvxSuperContourDlg& rDlg; + +protected: + + virtual void StateChanged( 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 m_xContourWnd; + std::unique_ptr m_xStbStatusColor; + std::unique_ptr m_xTbx1; + std::unique_ptr m_xMtfTolerance; + std::unique_ptr m_xStbStatus2; + std::unique_ptr m_xStbStatus3; + std::unique_ptr m_xCancelBtn; + std::unique_ptr m_xStbStatusColorWeld; + std::unique_ptr 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(const OString& rId); + void SetActivePoly(const OString& 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..593b459c5 --- /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 +#include +#include +#include +#include +#include +#include +#include + +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, + OBJ_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(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( 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() ).IsInside( 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.IsInside( 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(PushFlags::LINECOLOR |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(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 +#include + +class ContourWindow final : public GraphCtrl +{ + tools::PolyPolygon aPolyPoly; + Color aPipetteColor; + tools::Rectangle aWorkRect; + Link aPipetteLink; + Link aPipetteClickLink; + Link 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& rLink ) { aPipetteLink = rLink; } + void SetPipetteClickHdl( const Link& rLink ) { aPipetteClickLink = rLink; } + void SetWorkplaceClickHdl( const Link& 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..0f56078b5 --- /dev/null +++ b/svx/source/dialog/crashreportdlg.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/. + */ + +#include "crashreportdlg.hxx" + + +#include +#include +#include + +#include +#include + +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")) +{ + 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)); +} + +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..f913cabac --- /dev/null +++ b/svx/source/dialog/crashreportdlg.hxx @@ -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/. + */ + +#ifndef INCLUDED_SVX_SOURCE_DIALOG_CRASHREPORTDLG_HXX +#define INCLUDED_SVX_SOURCE_DIALOG_CRASHREPORTDLG_HXX + +#include + +class CrashReportDialog : public weld::GenericDialogController +{ +public: + explicit CrashReportDialog(weld::Window* pParent); + virtual short run() override; + virtual ~CrashReportDialog() override; + +private: + std::unique_ptr mxBtnSend; + std::unique_ptr mxBtnCancel; + std::unique_ptr mxBtnClose; + std::unique_ptr mxEditPreUpload; + std::unique_ptr mxEditPostUpload; + std::unique_ptr mxFtBugReport; + std::unique_ptr mxCBSafeMode; + + 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 +#include +#include + +#include + +#include + +#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 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..3116ec7ec --- /dev/null +++ b/svx/source/dialog/ctredlin.cxx @@ -0,0 +1,1023 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 xWriterControl, + std::unique_ptr 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(); + } +} + +void SvxRedlinTable::set_size_request(int nWidth, int nHeight) +{ + if (xWriterTreeView) + xWriterTreeView->set_size_request(nWidth, nHeight); + if (xCalcTreeView) + xCalcTreeView->set_size_request(nWidth, nHeight); +} + +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 = reinterpret_cast(pTreeView->get_id(rLeft).toInt64()); + RedlinData *pRightData = reinterpret_cast(pTreeView->get_id(rRight).toInt64()); + + 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 = reinterpret_cast(pTreeView->get_id(rLeft).toInt64()); + RedlinData *pRightData = reinterpret_cast(pTreeView->get_id(rRight).toInt64()); + + 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(const OUString &rAuthorStr, + const DateTime &rDateTime, + const OUString &rCommentStr) +{ + return IsValidEntry(rAuthorStr, rDateTime) && IsValidComment(rCommentStr); +} + +bool SvxRedlinTable::IsValidEntry(const OUString &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, weld::Window* pDialog, weld::Builder* pTopLevel) + : SvxTPage(pParent, "svx/ui/redlineviewpage.ui", "RedlineViewPage") + , bEnableAccept(true) + , bEnableAcceptAll(true) + , bEnableReject(true) + , bEnableRejectAll(true) + , bEnableUndo(true) + , bEnableClearFormat(false) + , bEnableClearFormatAll(false) + , m_pDialog(pDialog) + , m_xAccept(pTopLevel->weld_button("accept")) + , m_xReject(pTopLevel->weld_button("reject")) + , m_xAcceptAll(pTopLevel->weld_button("acceptall")) + , m_xRejectAll(pTopLevel->weld_button("rejectall")) + , m_xUndo(pTopLevel->weld_button("undo")) + , m_xViewData(new SvxRedlinTable(m_xBuilder->weld_tree_view("writerchanges"), + m_xBuilder->weld_tree_view("calcchanges"))) +{ + Size aControlSize(80, 65); + m_xViewData->set_size_request(aControlSize.Width(), aControlSize.Height()); + + Link 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 aWidths; + aWidths.push_back(nDigitWidth * 10); + aWidths.push_back(nDigitWidth * 20); + aWidths.push_back(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 aWidths; + aWidths.push_back(nDigitWidth * 20); + aWidths.push_back(nDigitWidth * 20); + aWidths.push_back(nDigitWidth * 20); + aWidths.push_back(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::EnableClearFormatButton(weld::Button& rButton, bool bFlag) +{ + OUString sText = rButton.get_label(); + OUString sClearFormat = SvxResId(RID_SVXSTR_CLEARFORM); + sal_Int32 nPos = sText.indexOf(sClearFormat); + + // add or remove "Clear formatting" to get "Reject" or "Reject/Clear formatting" + if (bFlag) + { + if (nPos == -1) + { + rButton.set_label(sText + "/" + sClearFormat); + } + } + else + { + if (nPos > 0) + { + rButton.set_label(sText.copy(0, nPos - 1)); + } + } + + if (m_pDialog) + { + // tdf#127218 allow dialog to shrink + m_pDialog->resize_to_request(); + } +} + +void SvxTPView::EnableClearFormat(bool bFlag) +{ + if (bEnableClearFormat == bFlag) + return; + EnableClearFormatButton(*m_xReject, bFlag); + bEnableClearFormat = bFlag; +} + +void SvxTPView::EnableClearFormatAll(bool bFlag) +{ + if (bEnableClearFormatAll == bFlag) + return; + EnableClearFormatButton(*m_xRejectAll, bFlag); + 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_time_spin_button("starttime", TimeFieldFormat::F_NONE)) + , 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_time_spin_button("endtime", TimeFieldFormat::F_NONE)) + , 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_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 aLink=LINK( this, SvxTPFilter, RowEnableHdl) ; + m_xCbDate->connect_clicked(aLink); + m_xCbAuthor->connect_clicked(aLink); + m_xCbRange->connect_clicked(aLink); + m_xCbAction->connect_clicked(aLink); + m_xCbComment->connect_clicked(aLink); + + Link a2Link=LINK(this, SvxTPFilter, ModifyDate); + m_xDfDate->connect_activated(a2Link); + m_xDfDate2->connect_activated(a2Link); + + Link a3Link=LINK(this, SvxTPFilter, ModifyTime); + m_xTfDate->connect_value_changed(a3Link); + m_xTfDate2->connect_value_changed(a3Link); + + Link 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 ); + m_xDfDate->set_date(aDateTime); + m_xDfDate2->set_date(aDateTime); + m_xTfDate->set_value(aDateTime); + m_xTfDate2->set_value(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_xTfDate->get_value(); +} + +void SvxTPFilter::SetFirstTime(const tools::Time &aTime) +{ + m_xTfDate->set_value(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_xTfDate2->get_value(); +} + +void SvxTPFilter::SetLastTime(const tools::Time &aTime) +{ + m_xTfDate2->set_value(aTime); +} + +void SvxTPFilter::SetDateMode(sal_uInt16 nMode) +{ + m_xLbDate->set_active(nMode); + SelDateHdl(*m_xLbDate); +} + +SvxRedlinDateMode SvxTPFilter::GetDateMode() const +{ + return static_cast(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(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::Button&, 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()) + { + m_xDfDate->set_date(aDateTime); + m_xTfDate->set_value(aDateTime); + } + else if (&rIB == m_xIbClock2.get()) + { + m_xDfDate2->set_date(aDateTime); + m_xTfDate2->set_value(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(m_xDfDate->get_date()); + m_pRedlinTable->SetLastDate(m_xDfDate2->get_date()); + m_pRedlinTable->SetFirstTime(m_xTfDate->get_value()); + m_pRedlinTable->SetLastTime(m_xTfDate2->get_value()); + 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::TimeSpinButton&, rTF, void) +{ + tools::Time aTime(0); + if (m_xTfDate.get() == &rTF) + { + if (m_xTfDate->get_text().isEmpty()) + m_xTfDate->set_value(aTime); + + if(m_pRedlinTable!=nullptr) + m_pRedlinTable->SetFirstTime(m_xTfDate->get_value()); + } + else if (m_xTfDate2.get() == &rTF) + { + if (m_xTfDate2->get_text().isEmpty()) + m_xTfDate2->set_value(aTime); + + if(m_pRedlinTable!=nullptr) + m_pRedlinTable->SetLastTime(m_xTfDate2->get_value()); + + } + bModified=true; +} + +IMPL_LINK_NOARG(SvxTPFilter, RefHandle, weld::Button&, void) +{ + aRefLink.Call(this); +} + +SvxAcceptChgCtr::SvxAcceptChgCtr(weld::Container* pParent, weld::Window* pDialog, weld::Builder* pTopLevel) + : 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"), pDialog, pTopLevel)); + m_xTPFilter->SetRedlinTable(m_xTPView->GetTableControl()); + m_xTabCtrl->set_current_page("view"); + m_xTabCtrl->show(); +} + +SvxAcceptChgCtr::~SvxAcceptChgCtr() +{ +} + +void SvxAcceptChgCtr::ShowFilterPage() +{ + m_xTabCtrl->set_current_page("filter"); +} + +IMPL_LINK(SvxAcceptChgCtr, ActivatePageHdl, const OString&, rPage, void) +{ + if (rPage == "filter") + m_xTPFilter->ActivatePage(); + else if (rPage == "view") + m_xTPView->ActivatePage(); +} + +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..93efd7cbc --- /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 + +#include +#include + +#include +#include + +namespace svx +{ + sal_uInt16 administrateDatabaseRegistration(weld::Window* parentWindow) + { + sal_uInt16 nResult = RET_CANCEL; + + SfxItemSet aRegistrationItems( SfxGetpApp()->GetPool(), svl::Items{} ); + + SvxAbstractDialogFactory* pDialogFactory = SvxAbstractDialogFactory::Create(); + ScopedVclPtr 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..7faf0d985 --- /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 +#include +#include +#include +#include +#include +#include +#include + +namespace svx { + +const 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, sal_Int32 nAngle ) +{ + double fAngle = basegfx::deg2rad(nAngle) / 100.0; + 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( static_cast< short >( (nAngle + 5) / 10 ) ); // Font uses 1/10 degrees + aFont.SetWeight( WEIGHT_BOLD ); + SetFont( aFont ); + + long nX = static_cast< long >( mnCenterX - fWidth * fCos - fHeight * fSin ); + long nY = static_cast< 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) != 0; + SetLineColor( GetButtonLineColor() ); + SetFillColor( GetButtonFillColor( bMain ) ); + + long nX = mnCenterX - static_cast< long >( (DIAL_OUTER_WIDTH / 2 - mnCenterX) * fCos ); + long nY = mnCenterY - static_cast< long >( (mnCenterY - DIAL_OUTER_WIDTH / 2) * fSin ); + 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); + long nX = static_cast< long >( -mnCenterX * cos( fAngle ) ); + long nY = static_cast< 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::Create(rReference)), + mxBmpDisabled(VclPtr::Create(rReference)), + mxBmpBuffered(VclPtr::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] + 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(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(""); + } +} + +sal_Int32 DialControl::GetRotation() const +{ + return mpImpl->mnAngle; +} + +void DialControl::SetRotation(sal_Int32 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()); + } + // 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(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(sal_Int32 nAngle, bool bBroadcast) +{ + bool bOldSel = mpImpl->mbNoRot; + mpImpl->mbNoRot = false; + + while (nAngle < 0) + nAngle += 36000; + + if (!bOldSel || (mpImpl->mnAngle != nAngle)) + { + mpImpl->mnAngle = nAngle; + InvalidateControl(); + if( mpImpl->mpLinkField ) + mpImpl->mpLinkField->set_value(GetRotation() / mpImpl->mnLinkedFieldValueMultiplyer, FieldUnit::DEGREE); + if( bBroadcast ) + mpImpl->maModifyHdl.Call(*this); + } +} + +void DialControl::SetModifyHdl( const Link& rLink ) +{ + mpImpl->maModifyHdl = rLink; +} + +void DialControl::HandleMouseEvent( const Point& rPos, bool bInitial ) +{ + long nX = rPos.X() - mpImpl->mnCenterX; + 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 = static_cast(basegfx::rad2deg(fAngle) * 100.0); + 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(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..cba8fbcc9 --- /dev/null +++ b/svx/source/dialog/dialmgr.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 +#include + +std::locale SvxResLocale() +{ + return Translate::Create("svx"); +} + +OUString SvxResId(const char* pId) +{ + return Translate::get(pId, 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..2a2e58dab --- /dev/null +++ b/svx/source/dialog/dlgctl3d.cxx @@ -0,0 +1,1182 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; + +Svx3DPreviewControl::Svx3DPreviewControl() + : mpFmPage(nullptr) + , 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() +{ + 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 + mpFmPage = new FmFormPage( *mpModel ); + mpModel->InsertPage( mpFmPage, 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 ); + mpFmPage->InsertObject( mpScene ); + + basegfx::B3DHomMatrix aRotation; + aRotation.rotate(DEG2RAD( 25 ), 0.0, 0.0); + aRotation.rotate(0.0, DEG2RAD( 40 ), 0.0); + mpScene->SetTransform(aRotation * mpScene->GetTransform()); + + // invalidate SnapRects of objects + mpScene->SetRectsDirty(); + + SfxItemSet aSet( mpModel->GetItemPool(), + svl::Items{} ); + 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( mpFmPage ); + mp3DView->hideMarkHandles(); + + // mark scene + mp3DView->MarkObj( mpScene, pPageView ); +} + +void Svx3DPreviewControl::Resize() +{ + // size of page + Size aSize(GetOutputSizePixel()); + aSize = GetDrawingArea()->get_ref_device().PixelToLogic(aSize); + mpFmPage->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) + { + SfxItemSet aSet(mpModel->GetItemPool(), svl::Items{}); + 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) + +static const sal_Int32 g_nInteractionStartDistance = 5 * 5 * 2; + +Svx3DLightControl::Svx3DLightControl() +: maChangeCallback(), + maSelectionChangeCallback(), + maSelectedLight(NO_LIGHT_SELECTED), + mpExpansionObject(nullptr), + mpLampBottomObject(nullptr), + mpLampShaftObject(nullptr), + maLightObjects(MAX_NUMBER_LIGHTS, nullptr), + mfRotateX(-20.0), + mfRotateY(45.0), + mfRotateZ(0.0), + maActionStartPoint(), + 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(F_PI2, 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, F_2PI - F_PI2, F_PI2)); + 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->SetRectsDirty(); +} + +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) + { + 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()) + { + // 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 += F_2PI; + } + + while(fNewRotY >= F_2PI) + { + fNewRotY -= F_2PI; + } + + // cut vertical + if(fNewRotX < -F_PI2) + { + fNewRotX = -F_PI2; + } + + if(fNewRotX > F_PI2) + { + fNewRotX = F_PI2; + } + + SetRotation(fNewRotX, fNewRotY, mfSaveActionStartRotZ); + + if(maChangeCallback.IsSet()) + { + maChangeCallback.Call(this); + } + } + else + { + // interaction in progress + double fNewPosHor = mfSaveActionStartHor + static_cast(aDeltaPos.X()); + double fNewPosVer = mfSaveActionStartVer - static_cast(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())); + mpFmPage->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()) + F_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) - F_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()) + { + if(mfRotateX != fVer || mfRotateY != fHor) + { + 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()) + { + if(fRotX != mfRotateX || fRotY != mfRotateY || fRotZ != mfRotateZ) + { + 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()); //acknowledge we first remove the old one + pArea->connect_key_press(LINK(this, SvxLightCtl3D, KeyInput)); + + pArea->connect_focus_in(Link()); //acknowledge we first remove the old one + pArea->connect_focus_in(LINK(this, SvxLightCtl3D, FocusIn)); + + // check selection + CheckSelection(); +} + +SvxLightCtl3D::~SvxLightCtl3D() +{ +} + +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(nHor) / 100.0, + static_cast((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..75f9319fc --- /dev/null +++ b/svx/source/dialog/dlgctrl.cxx @@ -0,0 +1,1459 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, RectPoint eRpt, sal_uInt16 nBorder) + : m_pPage(pPage) + , nBorderWidth(Application::GetDefaultDevice()->LogicToPixel(Size(nBorder, 0), MapMode(MapUnit::Map100thMM)).Width()) + , eRP(eRpt) + , eDefRP(eRpt) + , 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(); + pAccContext.clear(); +} + +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(); + + // Send accessibility event. + if (pAccContext.is()) + { + pAccContext->FireChildFocus(GetActualRP()); + } +} + +void SvxRectCtl::LoseFocus() +{ + Invalidate(); +} + +Point SvxRectCtl::GetApproxLogPtFromPixPt( const Point& rPt ) const +{ + Point aPt = rPt; + long x; + 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(); + + // notify accessibility object about change + if (pAccContext.is()) + pAccContext->selectChild( eNewRP /* MT, bFireFocus */ ); +} + +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(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() +{ + pAccContext = new SvxRectCtlAccessibleContext(this); + return pAccContext.get(); +} + +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 (!m_xAccess.is()) + m_xAccess = new SvxPixelCtlAccessible(this); + return m_xAccess.get(); +} + +long SvxPixelCtl::PointToIndex(const Point &aPt) const +{ + long nX = aPt.X() * nLines / aRectSize.Width(); + long nY = aPt.Y() * nLines / aRectSize.Height(); + + return nX + nY * nLines ; +} + +Point SvxPixelCtl::IndexToPoint(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; +} + +long SvxPixelCtl::GetFocusPosIndex() const +{ + return aFocusPosition.getX() + aFocusPosition.getY() * nLines ; +} + +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(); + } + + long nIndex = ShowPosition(rMEvt.GetPosPixel()); + + if(m_xAccess.is()) + { + m_xAccess->NotifyChild(nIndex,true, true); + } + + 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(aRectSize.Height() * i / nLines); + rRenderContext.DrawLine(Point(0, nTmp), Point(aRectSize.Width(), nTmp)); + // vertically + nTmp = static_cast( 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 ) +{ + long nLeft,nTop,nRight,nBottom; + 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(m_xAccess.is()) + { + 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; + } + } + return true; + } + else + { + return CustomWidgetController::KeyInput( rKEvt ); + } +} + +//Draw focus when get focus +void SvxPixelCtl::GetFocus() +{ + Invalidate(implCalFocusRect(aFocusPosition)); + + if (m_xAccess.is()) + { + m_xAccess->NotifyChild(GetFocusPosIndex(),true,false); + } +} + +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 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 + + long nCount = pList->Count(); + m_xControl->freeze(); + + for( 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 pControl) + : m_xControl(std::move(pControl)) +{ +} + +void SvxLineEndLB::Fill( const XLineEndListRef &pList, bool bStart ) +{ + if( !pList.is() ) + return; + + long nCount = pList->Count(); + ScopedVclPtrInstance< VirtualDevice > pVD; + m_xControl->freeze(); + + for( 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 DrawObectA + 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 DrawObectB + 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 DrawObectC + 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(), OBJ_LINE); + mpLineObjB = new SdrPathObj(getModel(), OBJ_PLIN); + mpLineObjC = new SdrPathObj(getModel(), OBJ_PLIN); + + 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(), 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(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(), 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::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(PushFlags::MAPMODE); + rRenderContext.SetMapMode(MapMode(MapUnit::Map100thMM)); + LocalPrePaint(rRenderContext); + + sdr::contact::SdrObjectVector aObjectVector; + + aObjectVector.push_back(mpRectangleObject); + + sdr::contact::ObjectContactOfObjListPainter aPainter(getBufferDevice(), 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& 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 xBuilder(Application::CreateBuilder(&rToolbar, "svx/ui/measurewidthbar.ui")); + std::unique_ptr xToolbar1(xBuilder->weld_toolbar("measurewidth1")); + std::unique_ptr xDispatcher1(new ToolbarUnoDispatcher(*xToolbar1, *xBuilder, rFrame)); + std::unique_ptr xToolbar2(xBuilder->weld_toolbar("measurewidth2")); + std::unique_ptr xDispatcher2(new ToolbarUnoDispatcher(*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..108e2b5e3 --- /dev/null +++ b/svx/source/dialog/dlgunit.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_DIALOG_DLGUNIT_HXX +#define INCLUDED_SVX_SOURCE_DIALOG_DLGUNIT_HXX + +#include +#include +#include + +inline OUString GetUnitString( 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..9ed2e2bdb --- /dev/null +++ b/svx/source/dialog/dlgutil.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 +#include +#include +#include +#include +#include +#include +#include +#include + + +FieldUnit GetModuleFieldUnit( const SfxItemSet& rSet ) +{ + FieldUnit eUnit = FieldUnit::INCH; + const SfxPoolItem* pItem = nullptr; + if ( SfxItemState::SET == rSet.GetItemState( SID_ATTR_METRIC, false, &pItem ) ) + eUnit = static_cast(static_cast(pItem)->GetValue()); + else + { + return SfxModule::GetCurrentFieldUnit(); + } + + return eUnit; +} + +bool GetApplyCharUnit( const SfxItemSet& rSet ) +{ + bool bUseCharUnit = false; + const SfxPoolItem* pItem = nullptr; + if ( SfxItemState::SET == rSet.GetItemState( SID_ATTR_APPLYCHARUNIT, false, &pItem ) ) + bUseCharUnit = static_cast(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 = static_cast(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..f8f7c61fc --- /dev/null +++ b/svx/source/dialog/docrecovery.cxx @@ -0,0 +1,1099 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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); + lCopyArgs[0].Name = PROP_DISPATCHASYNCHRON; + lCopyArgs[0].Value <<= false; + lCopyArgs[1].Name = PROP_SAVEPATH; + lCopyArgs[1].Value <<= rPath; + lCopyArgs[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; + + lCopyArgs[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); + lCopyArgs[0].Name = PROP_DISPATCHASYNCHRON; + lCopyArgs[0].Value <<= false; + lCopyArgs[1].Name = PROP_SAVEPATH; + lCopyArgs[1].Value <<= rPath; + lCopyArgs[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; + + lCopyArgs[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); + lRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON; + lRemoveArgs[0].Value <<= false; + lRemoveArgs[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; + + lRemoveArgs[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); + lRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON; + lRemoveArgs[0].Value <<= false; + lRemoveArgs[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) + { + lRemoveArgs[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); + lRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON; + lRemoveArgs[0].Value <<= false; + lRemoveArgs[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; + + lRemoveArgs[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(1); + lArgs[0].Name = PROP_DISPATCHASYNCHRON; + lArgs[0].Value <<= 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(2); + lArgs[0].Name = PROP_STATUSINDICATOR; + lArgs[0].Value <<= m_xProgress; + lArgs[1].Name = PROP_DISPATCHASYNCHRON; + lArgs[1].Value <<= 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(2); + lArgs[0].Name = PROP_STATUSINDICATOR; + lArgs[0].Value <<= m_xProgress; + lArgs[1].Name = PROP_DISPATCHASYNCHRON; + lArgs[1].Value <<= 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(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 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); + PluginProgress* pProgress = new PluginProgress(m_xProgressBar.get()); + m_xProgress.set(static_cast< css::task::XStatusIndicator* >(pProgress), css::uno::UNO_QUERY_THROW); +} + +SaveProgressDialog::~SaveProgressDialog() +{ + css::uno::Reference 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, const char* pRes) +{ + std::unique_ptr 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); + PluginProgress* pProgress = new PluginProgress(m_xProgressBar.get()); + m_xProgress.set(static_cast< css::task::XStatusIndicator* >(pProgress), css::uno::UNO_QUERY_THROW); + + std::vector aWidths; + aWidths.push_back(m_xFileListLB->get_checkbox_column_width()); + aWidths.push_back(60 * nWidth / 100); + aWidths.push_back(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, OUString::number(reinterpret_cast(&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 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::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 = reinterpret_cast(m_xFileListLB->get_id(i).toInt64()); + 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 = reinterpret_cast(m_xFileListLB->get_id(i).toInt64()); + 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(OUString::number(reinterpret_cast(&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 = + css::ui::dialogs::FolderPicker::create( m_pCore->getComponentContext() ); + + 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..6dd3e62c5 --- /dev/null +++ b/svx/source/dialog/fntctrl.cxx @@ -0,0 +1,1108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +// Item set includes +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//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,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, long& nHeight, 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 + */ +bool CleanAndCheckEmpty(OUString& rText) +{ + bool bEmpty = true; + for (sal_Int32 i = 0; i < rText.getLength(); ++i) + { + if (0xa == rText[i] || 0xd == rText[i]) + rText = rText.replaceAt(i, 1, " "); + else + bEmpty = false; + } + return bEmpty; +} +} // end anonymous namespace + +class FontPrevWin_Impl +{ + friend class SvxFontPrevWindow; + + SvxFont maFont; + VclPtr mpPrinter; + bool mbDelPrinter; + + Reference mxBreak; + std::vector maTextWidth; + std::deque maScriptChg; + std::vector maScriptType; + SvxFont maCJKFont; + SvxFont maCTLFont; + OUString maText; + OUString maScriptText; + std::unique_ptr mpColor; + std::unique_ptr mpBackColor; + std::unique_ptr mpTextLineColor; + std::unique_ptr mpOverlineColor; + long mnAscent; + sal_Unicode mcStartBracket; + sal_Unicode mcEndBracket; + + long mn100PercentFontWidth; // initial -1 -> not set yet + long mn100PercentFontWidthCJK; + 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) + { + SvtLanguageOptions aLanguageOptions; + m_bCJKEnabled = aLanguageOptions.IsAnyEnabled(); + m_bCTLEnabled = aLanguageOptions.IsCTLFontEnabled(); + + 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 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; + } + long nTxtWidth = 0; + long nCJKHeight = 0; + long nCTLHeight = 0; + long nHeight = 0; + mnAscent = 0; + long nCJKAscent = 0; + long nCTLAscent = 0; + + do + { + const SvxFont& rFont = (nScript == css::i18n::ScriptType::ASIAN) ? + maCJKFont : + ((nScript == css::i18n::ScriptType::COMPLEX) ? + maCTLFont : + rInFont); + 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(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( rSet.Get( nWhich ) ); + rFont.SetItalic( rItem.GetValue() != ITALIC_NONE ? ITALIC_NORMAL : ITALIC_NONE ); + } + + if( GetWhich( rSet, nWeight, nWhich ) ) + { + const SvxWeightItem& rItem = static_cast( 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) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + svtools::ColorConfig aColorConfig; + Color aTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor); + rRenderContext.SetTextColor(aTextColor); + + rRenderContext.SetBackground(rStyleSettings.GetWindowColor()); +} + +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::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->mpColor.reset(new Color(rColor)); + Invalidate(); +} + +void SvxFontPrevWindow::ResetColor() +{ + pImpl->mpColor.reset(); + Invalidate(); +} + +void SvxFontPrevWindow::SetBackColor(const Color &rColor) +{ + pImpl->mpBackColor.reset(new Color(rColor)); + Invalidate(); +} + +void SvxFontPrevWindow::SetTextLineColor(const Color &rColor) +{ + pImpl->mpTextLineColor.reset(new Color(rColor)); + Invalidate(); +} + +void SvxFontPrevWindow::SetOverlineColor(const Color &rColor) +{ + pImpl->mpOverlineColor.reset(new Color(rColor)); + Invalidate(); +} + +void SvxFontPrevWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + rRenderContext.Push(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 = pSh->GetSelectionText(); + pImpl->mbGetSelection = true; + pImpl->mbSelection = !CleanAndCheckEmpty(pImpl->maText); + } + + 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); + } + + bool bEmpty = CleanAndCheckEmpty(pImpl->maText); + if (bEmpty) + pImpl->maText = OUString(); + + 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()); + + long nX = aLogSize.Width() / 2 - aTxtSize.Width() / 2; + long nY = aLogSize.Height() / 2 - aTxtSize.Height() / 2; + + if (nY + pImpl->mnAscent > aLogSize.Height()) + nY = aLogSize.Height() - pImpl->mnAscent; + + if (pImpl->mpBackColor) + { + tools::Rectangle aRect(Point(0, 0), aLogSize); + Color aLineCol = rRenderContext.GetLineColor(); + Color aFillCol = rRenderContext.GetFillColor(); + rRenderContext.SetLineColor(); + rRenderContext.SetFillColor(*pImpl->mpBackColor); + rRenderContext.DrawRect(aRect); + rRenderContext.SetLineColor(aLineCol); + rRenderContext.SetFillColor(aFillCol); + } + if (pImpl->mpColor) + { + tools::Rectangle aRect(Point(nX, nY), aTxtSize); + Color aLineCol = rRenderContext.GetLineColor(); + Color aFillCol = rRenderContext.GetFillColor(); + rRenderContext.SetLineColor(); + rRenderContext.SetFillColor(*pImpl->mpColor); + rRenderContext.DrawRect(aRect); + rRenderContext.SetLineColor(aLineCol); + rRenderContext.SetFillColor(aFillCol); + } + + if (pImpl->mpTextLineColor) + { + rRenderContext.SetTextLineColor(*pImpl->mpTextLineColor); + } + + if (pImpl->mpOverlineColor) + { + rRenderContext.SetOverlineColor(*pImpl->mpOverlineColor); + } + + long nStdAscent = pImpl->mnAscent; + nY += nStdAscent; + + if (IsTwoLines()) + { + SvxFont aSmallFont(rFont); + Size aOldSize = pImpl->maCJKFont.GetFontSize(); + setFontSize(aSmallFont); + setFontSize(pImpl->maCJKFont); + + long nStartBracketWidth = 0; + long nEndBracketWidth = 0; + 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(); + long nResultWidth = nStartBracketWidth; + nResultWidth += nEndBracketWidth; + nResultWidth += nTextWidth; + + long _nX = (aLogSize.Width() - nResultWidth) / 2; + rRenderContext.DrawLine(Point(0, nY), Point(_nX, nY)); + rRenderContext.DrawLine(Point(_nX + nResultWidth, nY), Point(aLogSize.Width(), nY)); + + long nSmallAscent = pImpl->mnAscent; + 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() +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + Color aFontColor(rStyleSettings.GetWindowTextColor()); + + if (COL_AUTO == pImpl->maFont.GetColor()) + pImpl->maFont.SetColor(aFontColor); + + if (COL_AUTO == pImpl->maCJKFont.GetColor()) + pImpl->maCJKFont.SetColor(aFontColor); + + if (COL_AUTO == pImpl->maCTLFont.GetColor()) + pImpl->maCTLFont.SetColor(aFontColor); +} + +void SvxFontPrevWindow::SetFontSize( const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont ) +{ + sal_uInt16 nWhich; + long nH; + if (GetWhich(rSet, nSlot, nWhich)) + { + nH = OutputDevice::LogicToLogic(static_cast(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(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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( rSet.Get( nWhich ) ); + const Color& rColor = rBrush.GetColor(); + bTransparent = rColor.GetTransparency() > 0; + rFont.SetFillColor( rColor ); + rCJKFont.SetFillColor( rColor ); + rCTLFont.SetFillColor( rColor ); + } + else + bTransparent = true; + + rFont.SetTransparent( bTransparent ); + rCJKFont.SetTransparent( bTransparent ); + rCTLFont.SetTransparent( bTransparent ); + + Color aBackCol( COL_TRANSPARENT ); + if( !bPreviewBackgroundToCharacter ) + { + if( GetWhich( rSet, SID_ATTR_BRUSH, nWhich ) ) + { + const SvxBrushItem& rBrush = static_cast( rSet.Get( nWhich ) ); + if( GPOS_NONE == rBrush.GetGraphicPos() ) + aBackCol = rBrush.GetColor(); + } + } + SetBackColor( aBackCol ); + + // 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( 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( rSet.Get( nWhich ) ); + short nKern = static_cast(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( 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( 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..33fd244be --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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::StateChanged( sal_uInt16 /*nSID*/, SfxItemState /*eState*/, + const SfxPoolItem* pItem ) +{ + switch ( GetId() ) + { + case SID_FORMTEXT_STYLE: + { + const XFormTextStyleItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextStyleItem expected"); + rFontWorkDlg.SetStyle_Impl(pStateItem); + break; + } + case SID_FORMTEXT_ADJUST: + { + const XFormTextAdjustItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextAdjustItem expected"); + rFontWorkDlg.SetAdjust_Impl(pStateItem); + break; + } + case SID_FORMTEXT_DISTANCE: + { + const XFormTextDistanceItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextDistanceItem expected"); + rFontWorkDlg.SetDistance_Impl(pStateItem); + break; + } + case SID_FORMTEXT_START: + { + const XFormTextStartItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextStartItem expected"); + rFontWorkDlg.SetStart_Impl(pStateItem); + break; + } + case SID_FORMTEXT_MIRROR: + { + const XFormTextMirrorItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextMirrorItem expected"); + rFontWorkDlg.SetMirror_Impl(pStateItem); + break; + } + case SID_FORMTEXT_HIDEFORM: + { + const XFormTextHideFormItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextHideFormItem expected"); + rFontWorkDlg.SetShowForm_Impl(pStateItem); + break; + } + case SID_FORMTEXT_OUTLINE: + { + const XFormTextOutlineItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextOutlineItem expected"); + rFontWorkDlg.SetOutline_Impl(pStateItem); + break; + } + case SID_FORMTEXT_SHADOW: + { + const XFormTextShadowItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowItem expected"); + rFontWorkDlg.SetShadow_Impl(pStateItem); + break; + } + case SID_FORMTEXT_SHDWCOLOR: + { + const XFormTextShadowColorItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowColorItem expected"); + rFontWorkDlg.SetShadowColor_Impl(pStateItem); + break; + } + case SID_FORMTEXT_SHDWXVAL: + { + const XFormTextShadowXValItem* pStateItem = + dynamic_cast( pItem ); + DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowXValItem expected"); + rFontWorkDlg.SetShadowXVal_Impl(pStateItem); + break; + } + case SID_FORMTEXT_SHDWYVAL: + { + const XFormTextShadowYValItem* pStateItem = + dynamic_cast( 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 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"), 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 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()) + { + // #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()) + { + // #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) + { + 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); + } + } + + 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..62d60094b --- /dev/null +++ b/svx/source/dialog/framelink.cxx @@ -0,0 +1,431 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include + + +using namespace ::com::sun::star; +using namespace editeng; + +namespace svx::frame +{ + +// Classes +void Style::implEnsureImplStyle() +{ + if(!maImplStyle) + { + maImplStyle = std::make_shared(); + } +} + +Style::Style() : + maImplStyle() +{ +} + +Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) : + maImplStyle(std::make_shared()) +{ + maImplStyle->mnType = nType; + maImplStyle->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 ) : + maImplStyle(std::make_shared()) +{ + maImplStyle->mnType = nType; + maImplStyle->mfPatternScale = fScale; + Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS ); +} + +Style::Style( const editeng::SvxBorderLine* pBorder, double fScale ) : + maImplStyle() +{ + if(nullptr != pBorder) + { + maImplStyle = std::make_shared(); + maImplStyle->mfPatternScale = fScale; + Set( pBorder, fScale ); + } +} + +void Style::Clear() +{ + if(maImplStyle) + { + maImplStyle.reset(); + } +} + +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 + */ + implEnsureImplStyle(); + implStyle* pTarget = maImplStyle.get(); + pTarget->mfPrim = rtl::math::round(nP ? nP : nS, 2); + pTarget->mfDist = rtl::math::round((nP && nS) ? nD : 0, 2); + pTarget->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 ) +{ + implEnsureImplStyle(); + implStyle* pTarget = maImplStyle.get(); + pTarget->maColorPrim = rColorPrim; + pTarget->maColorSecn = rColorSecn; + pTarget->maColorGap = rColorGap; + pTarget->mbUseGapColor = bUseGapColor; + Set( nP, nD, nS ); +} + +void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth ) +{ + if(nullptr == pBorder) + { + Clear(); + return; + } + + implEnsureImplStyle(); + implStyle* pTarget = maImplStyle.get(); + pTarget->maColorPrim = pBorder->GetColorOut(); + pTarget->maColorSecn = pBorder->GetColorIn(); + pTarget->maColorGap = pBorder->GetColorGap(); + pTarget->mbUseGapColor = pBorder->HasGapColor(); + + const sal_uInt16 nPrim(pBorder->GetOutWidth()); + const sal_uInt16 nDist(pBorder->GetDistance()); + const sal_uInt16 nSecn(pBorder->GetInWidth()); + + pTarget->mnType = pBorder->GetBorderLineStyle(); + pTarget->mfPatternScale = fScale; + + if( !nSecn ) // no or single frame border + { + Set( std::min(nPrim * fScale, nMaxWidth), 0, 0 ); + } + else + { + Set(std::min(nPrim * fScale, nMaxWidth), std::min(nDist * fScale, nMaxWidth), std::min(nSecn * fScale, nMaxWidth)); + // Enlarge the style if distance is too small due to rounding losses. + double nPixWidth = std::min((nPrim + nDist + nSecn) * fScale, nMaxWidth); + + if( nPixWidth > GetWidth() ) + { + pTarget->mfDist = nPixWidth - pTarget->mfPrim - pTarget->mfSecn; + } + + // Shrink the style if it is too thick for the control. + while( GetWidth() > nMaxWidth ) + { + // First decrease space between lines. + if (pTarget->mfDist) + { + --(pTarget->mfDist); + continue; + } + + // Still too thick? Decrease the line widths. + if (pTarget->mfPrim != 0.0 && rtl::math::approxEqual(pTarget->mfPrim, pTarget->mfSecn)) + { + // Both lines equal - decrease both to keep symmetry. + --(pTarget->mfPrim); + --(pTarget->mfSecn); + continue; + } + + // Decrease each line for itself + if (pTarget->mfPrim) + { + --(pTarget->mfPrim); + } + + if ((GetWidth() > nMaxWidth) && pTarget->mfSecn != 0.0) + { + --(pTarget->mfSecn); + } + } + } +} + +void Style::SetRefMode( RefMode eRefMode ) +{ + if(!maImplStyle) + { + if(RefMode::Centered == eRefMode) + { + return; + } + + implEnsureImplStyle(); + } + + maImplStyle->meRefMode = eRefMode; +} + +void Style::SetColorPrim( const Color& rColor ) +{ + if(!maImplStyle) + { + if(Color() == rColor) + { + return; + } + + implEnsureImplStyle(); + } + + maImplStyle->maColorPrim = rColor; +} + +void Style::SetColorSecn( const Color& rColor ) +{ + if(!maImplStyle) + { + if(Color() == rColor) + { + return; + } + + implEnsureImplStyle(); + } + + maImplStyle->maColorSecn = rColor; +} + +void Style::SetType( SvxBorderLineStyle nType ) +{ + if(!maImplStyle) + { + if(SvxBorderLineStyle::SOLID == nType) + { + return; + } + + implEnsureImplStyle(); + } + + maImplStyle->mnType = nType; +} + +Style& Style::MirrorSelf() +{ + if(!maImplStyle) + { + return *this; + } + + implStyle* pTarget = maImplStyle.get(); + + if (pTarget->mfSecn) + { + std::swap( pTarget->mfPrim, pTarget->mfSecn ); + // also need to swap colors + std::swap( pTarget->maColorPrim, pTarget->maColorSecn ); + } + + if( pTarget->meRefMode != RefMode::Centered ) + { + pTarget->meRefMode = (pTarget->meRefMode == RefMode::Begin) ? RefMode::End : RefMode::Begin; + } + + return *this; +} + +void Style::SetWordTableCell(bool bWordTableCell) +{ + if (!maImplStyle) + { + implEnsureImplStyle(); + } + + maImplStyle->mbWordTableCell = bWordTableCell; +} + +bool Style::operator==( const Style& rOther) const +{ + if(!maImplStyle && !rOther.maImplStyle) + { + return true; + } + + if(maImplStyle && rOther.maImplStyle && maImplStyle.get() == rOther.maImplStyle.get()) + { + return true; + } + + 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(!maImplStyle && !rOther.maImplStyle) + { + // are equal + return false; + } + + if (maImplStyle && maImplStyle->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 this this rOther.Dist(); + + // both lines single and 1 unit thick, only one is dotted -> this 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..dd8081bf3 --- /dev/null +++ b/svx/source/dialog/framelinkarray.cxx @@ -0,0 +1,1290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace svx::frame { + +namespace { + +class Cell +{ +private: + Style maLeft; + Style maRight; + Style maTop; + Style maBottom; + Style maTLBR; + Style maBLTR; + +public: + long mnAddLeft; + long mnAddRight; + long mnAddTop; + long 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 CreateCoordinateSystem(const Array& rArray, size_t nCol, size_t nRow, bool bExpandMerged) const; +}; + +} + +typedef std::vector< Cell > CellVec; + +basegfx::B2DHomMatrix Cell::CreateCoordinateSystem(const Array& rArray, size_t nCol, size_t nRow, bool bExpandMerged) const +{ + basegfx::B2DHomMatrix aRetval; + const basegfx::B2DRange aRange(rArray.GetCellRange(nCol, nRow, bExpandMerged)); + + if(!aRange.isEmpty()) + { + basegfx::B2DPoint aOrigin(aRange.getMinimum()); + basegfx::B2DVector aX(aRange.getWidth(), 0.0); + basegfx::B2DVector aY(0.0, aRange.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 + aRetval = basegfx::utils::createCoordinateSystemTransform(aOrigin, aX, aY); + } + + return aRetval; +} + +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& rCoords, const std::vector& 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, size_t nWidth, size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) +{ + for( size_t nCol = nFirstCol; nCol <= nLastCol; ++nCol ) + { + for( size_t 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; +} + + +static const Style OBJ_STYLE_NONE; +static const Cell OBJ_CELL_NONE; + +struct ArrayImpl +{ + CellVec maCells; + std::vector maWidths; + std::vector maHeights; + mutable std::vector maXCoords; + mutable std::vector maYCoords; + size_t mnWidth; + size_t mnHeight; + size_t mnFirstClipCol; + size_t mnFirstClipRow; + size_t mnLastClipCol; + size_t mnLastClipRow; + mutable bool mbXCoordsDirty; + mutable bool mbYCoordsDirty; + bool mbMayHaveCellRotation; + + explicit ArrayImpl( size_t nWidth, size_t nHeight ); + + bool IsValidPos( size_t nCol, size_t nRow ) const + { return (nCol < mnWidth) && (nRow < mnHeight); } + size_t GetIndex( size_t nCol, size_t nRow ) const + { return nRow * mnWidth + nCol; } + + const Cell& GetCell( size_t nCol, size_t nRow ) const; + Cell& GetCellAcc( size_t nCol, size_t nRow ); + + size_t GetMergedFirstCol( size_t nCol, size_t nRow ) const; + size_t GetMergedFirstRow( size_t nCol, size_t nRow ) const; + size_t GetMergedLastCol( size_t nCol, size_t nRow ) const; + size_t GetMergedLastRow( size_t nCol, size_t nRow ) const; + + const Cell& GetMergedOriginCell( size_t nCol, size_t nRow ) const; + + bool IsMergedOverlappedLeft( size_t nCol, size_t nRow ) const; + bool IsMergedOverlappedRight( size_t nCol, size_t nRow ) const; + bool IsMergedOverlappedTop( size_t nCol, size_t nRow ) const; + bool IsMergedOverlappedBottom( size_t nCol, size_t nRow ) const; + + bool IsInClipRange( size_t nCol, size_t nRow ) const; + bool IsColInClipRange( size_t nCol ) const; + bool IsRowInClipRange( size_t nRow ) const; + + size_t GetMirrorCol( size_t nCol ) const { return mnWidth - nCol - 1; } + + long GetColPosition( size_t nCol ) const; + long GetRowPosition( size_t nRow ) const; + + bool HasCellRotation() const; +}; + +ArrayImpl::ArrayImpl( size_t nWidth, size_t 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( size_t nCol, size_t nRow ) const +{ + return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : OBJ_CELL_NONE; +} + +Cell& ArrayImpl::GetCellAcc( size_t nCol, size_t nRow ) +{ + static Cell aDummy; + return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : aDummy; +} + +size_t ArrayImpl::GetMergedFirstCol( size_t nCol, size_t nRow ) const +{ + size_t nFirstCol = nCol; + while( (nFirstCol > 0) && GetCell( nFirstCol, nRow ).mbOverlapX ) --nFirstCol; + return nFirstCol; +} + +size_t ArrayImpl::GetMergedFirstRow( size_t nCol, size_t nRow ) const +{ + size_t nFirstRow = nRow; + while( (nFirstRow > 0) && GetCell( nCol, nFirstRow ).mbOverlapY ) --nFirstRow; + return nFirstRow; +} + +size_t ArrayImpl::GetMergedLastCol( size_t nCol, size_t nRow ) const +{ + size_t nLastCol = nCol + 1; + while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow ).mbOverlapX ) ++nLastCol; + return nLastCol - 1; +} + +size_t ArrayImpl::GetMergedLastRow( size_t nCol, size_t nRow ) const +{ + size_t nLastRow = nRow + 1; + while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow ).mbOverlapY ) ++nLastRow; + return nLastRow - 1; +} + +const Cell& ArrayImpl::GetMergedOriginCell( size_t nCol, size_t nRow ) const +{ + return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) ); +} + +bool ArrayImpl::IsMergedOverlappedLeft( size_t nCol, size_t nRow ) const +{ + const Cell& rCell = GetCell( nCol, nRow ); + return rCell.mbOverlapX || (rCell.mnAddLeft > 0); +} + +bool ArrayImpl::IsMergedOverlappedRight( size_t nCol, size_t nRow ) const +{ + return GetCell( nCol + 1, nRow ).mbOverlapX || (GetCell( nCol, nRow ).mnAddRight > 0); +} + +bool ArrayImpl::IsMergedOverlappedTop( size_t nCol, size_t nRow ) const +{ + const Cell& rCell = GetCell( nCol, nRow ); + return rCell.mbOverlapY || (rCell.mnAddTop > 0); +} + +bool ArrayImpl::IsMergedOverlappedBottom( size_t nCol, size_t nRow ) const +{ + return GetCell( nCol, nRow + 1 ).mbOverlapY || (GetCell( nCol, nRow ).mnAddBottom > 0); +} + +bool ArrayImpl::IsColInClipRange( size_t nCol ) const +{ + return (mnFirstClipCol <= nCol) && (nCol <= mnLastClipCol); +} + +bool ArrayImpl::IsRowInClipRange( size_t nRow ) const +{ + return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow); +} + +bool ArrayImpl::IsInClipRange( size_t nCol, size_t nRow ) const +{ + return IsColInClipRange( nCol ) && IsRowInClipRange( nRow ); +} + +long ArrayImpl::GetColPosition( size_t nCol ) const +{ + if( mbXCoordsDirty ) + { + lclRecalcCoordVec( maXCoords, maWidths ); + mbXCoordsDirty = false; + } + return maXCoords[ nCol ]; +} + +long ArrayImpl::GetRowPosition( size_t 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, size_t nCol, size_t nRow ); + + bool Is() const { return (mnCol <= mnLastCol) && (mnRow <= mnLastRow); } + size_t Col() const { return mnCol; } + size_t Row() const { return mnRow; } + + MergedCellIterator& operator++(); + +private: + size_t mnFirstCol; + size_t mnFirstRow; + size_t mnLastCol; + size_t mnLastRow; + size_t mnCol; + size_t mnRow; +}; + +} + +MergedCellIterator::MergedCellIterator( const Array& rArray, size_t nCol, size_t 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 ) + + +Array::Array() +{ + Initialize( 0, 0 ); +} + +Array::~Array() +{ +} + +// array size and column/row indexes +void Array::Initialize( size_t nWidth, size_t nHeight ) +{ + mxImpl.reset( new ArrayImpl( nWidth, nHeight ) ); +} + +size_t Array::GetColCount() const +{ + return mxImpl->mnWidth; +} + +size_t Array::GetRowCount() const +{ + return mxImpl->mnHeight; +} + +size_t Array::GetCellCount() const +{ + return mxImpl->maCells.size(); +} + +size_t Array::GetCellIndex( size_t nCol, size_t 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( size_t nCol, size_t nRow, const Style& rStyle ) +{ + DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" ); + CELLACC( nCol, nRow ).SetStyleLeft(rStyle); +} + +void Array::SetCellStyleRight( size_t nCol, size_t nRow, const Style& rStyle ) +{ + DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" ); + CELLACC( nCol, nRow ).SetStyleRight(rStyle); +} + +void Array::SetCellStyleTop( size_t nCol, size_t nRow, const Style& rStyle ) +{ + DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" ); + CELLACC( nCol, nRow ).SetStyleTop(rStyle); +} + +void Array::SetCellStyleBottom( size_t nCol, size_t nRow, const Style& rStyle ) +{ + DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" ); + CELLACC( nCol, nRow ).SetStyleBottom(rStyle); +} + +void Array::SetCellStyleTLBR( size_t nCol, size_t nRow, const Style& rStyle ) +{ + DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" ); + CELLACC( nCol, nRow ).SetStyleTLBR(rStyle); +} + +void Array::SetCellStyleBLTR( size_t nCol, size_t nRow, const Style& rStyle ) +{ + DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" ); + CELLACC( nCol, nRow ).SetStyleBLTR(rStyle); +} + +void Array::SetCellStyleDiag( size_t nCol, size_t 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( size_t nCol, const Style& rStyle ) +{ + DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleLeft" ); + for( size_t nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) + SetCellStyleLeft( nCol, nRow, rStyle ); +} + +void Array::SetColumnStyleRight( size_t nCol, const Style& rStyle ) +{ + DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleRight" ); + for( size_t nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) + SetCellStyleRight( nCol, nRow, rStyle ); +} + +void Array::SetRowStyleTop( size_t nRow, const Style& rStyle ) +{ + DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleTop" ); + for( size_t nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) + SetCellStyleTop( nCol, nRow, rStyle ); +} + +void Array::SetRowStyleBottom( size_t nRow, const Style& rStyle ) +{ + DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleBottom" ); + for( size_t nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) + SetCellStyleBottom( nCol, nRow, rStyle ); +} + +void Array::SetCellRotation(size_t nCol, size_t 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( size_t nCol, size_t 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( size_t nCol, size_t 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 ORIGCELL( 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( size_t nCol, size_t 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( size_t nCol, size_t 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 ORIGCELL( 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( size_t nCol, size_t nRow ) const +{ + return CELL( nCol, nRow ).GetStyleTLBR(); +} + +const Style& Array::GetCellStyleBLTR( size_t nCol, size_t nRow ) const +{ + return CELL( nCol, nRow ).GetStyleBLTR(); +} + +const Style& Array::GetCellStyleTL( size_t nCol, size_t nRow ) const +{ + // not in clipping range: always invisible + if( !mxImpl->IsInClipRange( nCol, nRow ) ) + return OBJ_STYLE_NONE; + // return style only for top-left cell + size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); + size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); + return ((nCol == nFirstCol) && (nRow == nFirstRow)) ? + CELL( nFirstCol, nFirstRow ).GetStyleTLBR() : OBJ_STYLE_NONE; +} + +const Style& Array::GetCellStyleBR( size_t nCol, size_t nRow ) const +{ + // not in clipping range: always invisible + if( !mxImpl->IsInClipRange( nCol, nRow ) ) + return OBJ_STYLE_NONE; + // return style only for bottom-right cell + size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); + size_t 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( size_t nCol, size_t nRow ) const +{ + // not in clipping range: always invisible + if( !mxImpl->IsInClipRange( nCol, nRow ) ) + return OBJ_STYLE_NONE; + // return style only for bottom-left cell + size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); + size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); + return ((nCol == nFirstCol) && (nRow == nLastRow)) ? + CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleBLTR() : OBJ_STYLE_NONE; +} + +const Style& Array::GetCellStyleTR( size_t nCol, size_t nRow ) const +{ + // not in clipping range: always invisible + if( !mxImpl->IsInClipRange( nCol, nRow ) ) + return OBJ_STYLE_NONE; + // return style only for top-right cell + size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); + size_t 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( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) +{ + DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetMergedRange" ); + DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetMergedRange" ); +#if OSL_DEBUG_LEVEL >= 2 + { + bool bFound = false; + for( size_t nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol ) + for( size_t 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( size_t nCol, size_t nRow, long 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( size_t nCol, size_t nRow, long 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( size_t nCol, size_t nRow, long 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( size_t nCol, size_t nRow, long 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( size_t nCol, size_t nRow ) const +{ + DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" ); + return CELL( nCol, nRow ).IsMerged(); +} + +void Array::GetMergedOrigin( size_t& rnFirstCol, size_t& rnFirstRow, size_t nCol, size_t nRow ) const +{ + DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetMergedOrigin" ); + rnFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); + rnFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); +} + +void Array::GetMergedRange( size_t& rnFirstCol, size_t& rnFirstRow, + size_t& rnLastCol, size_t& rnLastRow, size_t nCol, size_t nRow ) const +{ + GetMergedOrigin( rnFirstCol, rnFirstRow, nCol, nRow ); + rnLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); + rnLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); +} + +// clipping +void Array::SetClipRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t 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( long nXOffset ) +{ + mxImpl->maXCoords[ 0 ] = nXOffset; + mxImpl->mbXCoordsDirty = true; +} + +void Array::SetYOffset( long nYOffset ) +{ + mxImpl->maYCoords[ 0 ] = nYOffset; + mxImpl->mbYCoordsDirty = true; +} + +void Array::SetColWidth( size_t nCol, long nWidth ) +{ + DBG_FRAME_CHECK_COL( nCol, "SetColWidth" ); + mxImpl->maWidths[ nCol ] = nWidth; + mxImpl->mbXCoordsDirty = true; +} + +void Array::SetRowHeight( size_t nRow, long nHeight ) +{ + DBG_FRAME_CHECK_ROW( nRow, "SetRowHeight" ); + mxImpl->maHeights[ nRow ] = nHeight; + mxImpl->mbYCoordsDirty = true; +} + +void Array::SetAllColWidths( long nWidth ) +{ + std::fill( mxImpl->maWidths.begin(), mxImpl->maWidths.end(), nWidth ); + mxImpl->mbXCoordsDirty = true; +} + +void Array::SetAllRowHeights( long nHeight ) +{ + std::fill( mxImpl->maHeights.begin(), mxImpl->maHeights.end(), nHeight ); + mxImpl->mbYCoordsDirty = true; +} + +long Array::GetColPosition( size_t nCol ) const +{ + DBG_FRAME_CHECK_COL_1( nCol, "GetColPosition" ); + return mxImpl->GetColPosition( nCol ); +} + +long Array::GetRowPosition( size_t nRow ) const +{ + DBG_FRAME_CHECK_ROW_1( nRow, "GetRowPosition" ); + return mxImpl->GetRowPosition( nRow ); +} + +long Array::GetColWidth( size_t nFirstCol, size_t nLastCol ) const +{ + DBG_FRAME_CHECK_COL( nFirstCol, "GetColWidth" ); + DBG_FRAME_CHECK_COL( nLastCol, "GetColWidth" ); + return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol ); +} + +long Array::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const +{ + DBG_FRAME_CHECK_ROW( nFirstRow, "GetRowHeight" ); + DBG_FRAME_CHECK_ROW( nLastRow, "GetRowHeight" ); + return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow ); +} + +long Array::GetWidth() const +{ + return GetColPosition( mxImpl->mnWidth ) - GetColPosition( 0 ); +} + +long Array::GetHeight() const +{ + return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 ); +} + +basegfx::B2DRange Array::GetCellRange( size_t nCol, size_t nRow, bool bExpandMerged ) const +{ + if(bExpandMerged) + { + // get the Range of the fully expanded cell (if merged) + const size_t nFirstCol(mxImpl->GetMergedFirstCol( nCol, nRow )); + const size_t nFirstRow(mxImpl->GetMergedFirstRow( nCol, nRow )); + const size_t nLastCol(mxImpl->GetMergedLastCol( nCol, nRow )); + const size_t 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); + } + else + { + const Point aPoint( GetColPosition( nCol ), GetRowPosition( nRow ) ); + const Size aSize( GetColWidth( nCol, nCol ) + 1, GetRowHeight( nRow, nRow ) + 1 ); + const tools::Rectangle aRect(aPoint, aSize); + + return vcl::unotools::b2DRectangleFromRectangle(aRect); + } +} + +// mirroring +void Array::MirrorSelfX() +{ + CellVec aNewCells; + aNewCells.reserve( GetCellCount() ); + + size_t 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 ) + { + size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); + size_t 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, + size_t col, + size_t 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, + size_t col, + size_t 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); +} + +drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( + size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow, + const Color* pForceColor ) const +{ + DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "CreateB2DPrimitiveRange" ); + DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "CreateB2DPrimitiveRange" ); + + // 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 size_t nStartRow(nFirstRow > 0 ? nFirstRow - 1 : nFirstRow); + const size_t nEndRow(nLastRow < GetRowCount() - 1 ? nLastRow + 1 : nLastRow); + const size_t nStartCol(nFirstCol > 0 ? nFirstCol - 1 : nFirstCol); + const size_t nEndCol(nLastCol < GetColCount() - 1 ? nLastCol + 1 : nLastCol); + + // prepare SdrFrameBorderDataVector + std::shared_ptr aData( + std::make_shared()); + + // remember for which merged cells crossed lines were already created. To + // do so, hold the size_t cell index in a set for fast check + std::set< size_t > aMergedCells; + + for (size_t nRow(nStartRow); nRow <= nEndRow; ++nRow) + { + for (size_t 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.CreateCoordinateSystem(*this, nCol, nRow, false)); + 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 bSupressLeft(!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 + && !bSupressLeft) // 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); + } + } + + // check for crossed lines, these need special treatment, especially + // for merged cells, see below + const Style& rTLBR(GetCellStyleTLBR(nCol, nRow)); + const Style& rBLTR(GetCellStyleBLTR(nCol, nRow)); + + if(rTLBR.IsUsed() || rBLTR.IsUsed()) + { + bool bContinue(true); + + if(rCell.IsMerged()) + { + // first check if this merged cell was already handled. To do so, + // calculate and use the index of the TopLeft cell + const size_t _nMergedFirstCol(mxImpl->GetMergedFirstCol(nCol, nRow)); + const size_t _nMergedFirstRow(mxImpl->GetMergedFirstRow(nCol, nRow)); + const size_t nIndexOfMergedCell(mxImpl->GetIndex(_nMergedFirstCol, _nMergedFirstRow)); + bContinue = (aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell)); + + if(bContinue) + { + // not found, add now to mark as handled + aMergedCells.insert(nIndexOfMergedCell); + + // when merged, get extended coordinate system and derived values + // for the full range of this merged cell + aCoordinateSystem = rCell.CreateCoordinateSystem(*this, nCol, nRow, true); + aX = basegfx::utils::getColumn(aCoordinateSystem, 0); + aY = basegfx::utils::getColumn(aCoordinateSystem, 1); + aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2); + } + } + + if(bContinue) + { + if(rTLBR.IsUsed()) + { + /// top-left and bottom-right Style Tables + aData->emplace_back( + aOrigin, + aX + aY, + rTLBR, + pForceColor); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); + + /// Fill top-left Style Table + const Style& rTLFromRight(GetCellStyleTop(nCol, nRow)); + const Style& rTLFromBottom(GetCellStyleLeft(nCol, nRow)); + + rInstance.addSdrConnectStyleData(true, rTLFromRight, aX, false); + rInstance.addSdrConnectStyleData(true, rTLFromBottom, aY, false); + + /// Fill bottom-right Style Table + const Style& rBRFromBottom(GetCellStyleRight(nCol, nRow)); + const Style& rBRFromLeft(GetCellStyleBottom(nCol, nRow)); + + rInstance.addSdrConnectStyleData(false, rBRFromBottom, -aY, true); + rInstance.addSdrConnectStyleData(false, rBRFromLeft, -aX, true); + } + + if(rBLTR.IsUsed()) + { + /// bottom-left and top-right Style Tables + aData->emplace_back( + aOrigin + aY, + aX - aY, + rBLTR, + pForceColor); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); + + /// Fill bottom-left Style Table + const Style& rBLFromTop(GetCellStyleLeft(nCol, nRow)); + const Style& rBLFromBottom(GetCellStyleBottom(nCol, nRow)); + + rInstance.addSdrConnectStyleData(true, rBLFromTop, -aY, true); + rInstance.addSdrConnectStyleData(true, rBLFromBottom, aX, false); + + /// Fill top-right Style Table + const Style& rTRFromLeft(GetCellStyleTop(nCol, nRow)); + const Style& rTRFromBottom(GetCellStyleRight(nCol, nRow)); + + rInstance.addSdrConnectStyleData(false, rTRFromLeft, -aX, true); + rInstance.addSdrConnectStyleData(false, rTRFromBottom, aY, false); + } + } + } + } + else + { + // 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 + && !bSupressLeft) // 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 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) + } + + 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 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 + +namespace svx +{ +FrameDirectionListBox::FrameDirectionListBox(std::unique_ptr 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..b4d80e2f7 --- /dev/null +++ b/svx/source/dialog/frmsel.cxx @@ -0,0 +1,1277 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 long FRAMESEL_GEOM_OUTER = 2; + +/** Space between arrows and usable inner area. */ +const long FRAMESEL_GEOM_INNER = 3; + +/** Maximum width to draw a frame border style. */ +const long FRAMESEL_GEOM_WIDTH = 9; + +/** Additional margin for click area of outer lines. */ +const long FRAMESEL_GEOM_ADD_CLICK_OUTER = 5; + +/** Additional margin for click area of inner lines. */ +const 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 ).IsInside( 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::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 ), + maChildVec( 8 ) +{ + 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() + +{ + for( auto& rpChild : maChildVec ) + if( rpChild.is() ) + rpChild->Invalidate(); +} + +// 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(); + maBackCol = rSettings.GetFieldColor(); + mbHCMode = rSettings.GetHighContrastMode(); + maArrowCol = rSettings.GetFieldTextColor(); + maMarkCol.operator=(maBackCol).Merge(maArrowCol, mbHCMode ? 0x80 : 0xC0); + maHCLineCol = rSettings.GetLabelTextColor(); +} + +static const OUStringLiteral 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(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. */ + 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. */ + 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). */ + 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(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 ) ); + + 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, true )); + 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 ? F_PI2 - fHorDiagAngle : 0.0); + const long nDiagFocusOffsX(basegfx::fround(-mnFocusOffs / tan(fHorDiagAngle) + mnFocusOffs / sin(fHorDiagAngle))); + const 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). + */ + long nClO = FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_OUTER; + long nClI = (mbTLBR && mbBLTR) ? (FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_INNER) : nClO; + long nClH = mbHor ? nClI : nClO; // additional space dependent of horizontal inner border + 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 ) + { + 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, true )); + 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" ); + + 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; + + long nTLPos = 0; + 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( size_t nCol = 0; nCol < maArray.GetColCount(); ++nCol ) + for( size_t 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 pProcessor2D( + drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice( + *mpVirDev, + aNewViewInformation2D)); + + if (pProcessor2D) + { + 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; + 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(); + + if( eState == FrameBorderState::Show ) + SetBorderCoreStyle( rBorder, &maCurrStyle ); + else + rBorder.SetState( eState ); + if (xRet.is()) + xRet->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOld, aNew ); + 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); + Size aPrefSize = pDrawingArea->get_ref_device().LogicToPixel(Size(61, 65), MapMode(MapUnit::MapAppFont)); + pDrawingArea->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + mxImpl.reset( new FrameSelectorImpl( *this ) ); + EnableRTL( false ); // #107808# don't mirror the mouse handling +} + +FrameSelector::~FrameSelector() +{ + if( mxAccess.is() ) + mxAccess->Invalidate(); +} + +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( 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& FrameSelector::GetSelectHdl() const +{ + return mxImpl->maSelectHdl; +} + +void FrameSelector::SetSelectHdl( const Link& 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*/ ); + // 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 ); + } + } +} + +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( 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 ); +} + +// accessibility +Reference< XAccessible > FrameSelector::CreateAccessible() +{ + if( !mxAccess.is() ) + mxAccess = new a11y::AccFrameSelector(*this); + return mxAccess.get(); +} + +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 ) ).get(); +} + +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..d3e0671e5 --- /dev/null +++ b/svx/source/dialog/graphctl.cxx @@ -0,0 +1,841 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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(OBJ_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( mpAccContext.is() ) + { + mpAccContext->disposing(); + mpAccContext.clear(); + } + 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; + + 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 ); + 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); + + // Tell the accessibility object about the changes. + if (mpAccContext.is()) + mpAccContext->setModelAndView (pModel.get(), pView.get()); +} + +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.get(), 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 long nWidth = aWinSize.Width(); + const long nHeight = aWinSize.Height(); + double fGrfWH = static_cast(aGraphSize.Width()) / aGraphSize.Height(); + double fWinWH = static_cast(nWidth) / nHeight; + + // Adapt Bitmap to Thumb size + if ( fGrfWH < fWinWH) + { + aNewSize.setWidth( static_cast( static_cast(nHeight) * fGrfWH ) ); + aNewSize.setHeight( nHeight ); + } + else + { + aNewSize.setWidth( nWidth ); + aNewSize.setHeight( static_cast( static_cast(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(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: + { + long nX = 0; + 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.IsInside(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(rDragStat).SetNoSnap(); + if(bWasSnapEnabled) + pView->SetSnapEnabled(false); + + pView->MovAction(aEndPoint); + pView->EndDragObj(); + + // restore snap + if(!bWasNoSnap) + const_cast(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(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 ).IsInside( 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 ).IsInside( 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 = OBJ_NONE; + pView->SetCurrentObj( sal::static_int_cast< sal_uInt16 >( 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( sal::static_int_cast< sal_uInt16 >( eObjKind ) ); + } + else + eObjKind = OBJ_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 GraphCtrlView::CreateOverlayManager(OutputDevice& rDevice) const +{ + assert(&rDevice == &rGraphCtrl.GetDrawingArea()->get_ref_device()); + if (rDevice.GetOutDevType() == OUTDEV_VIRDEV) + { + rtl::Reference 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(mpAccContext == nullptr ) + { + // Disable accessibility if no model/view data available + if (pView && pModel) + mpAccContext = new SvxGraphCtrlAccessibleContext(*this); + } + return mpAccContext.get(); +} + +/* 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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + + +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 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 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 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 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 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 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..5065d67ac --- /dev/null +++ b/svx/source/dialog/hdft.cxx @@ -0,0 +1,1060 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +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 +static const long MINBODY = 56; // 1mm in twips rounded + +// default distance to Header or footer +static const long DEF_DIST_WRITER = 500; // 5mm (Writer) +static const long DEF_DIST_CALC = 250; // 2.5mm (Calc) + +const sal_uInt16 SvxHFPage::pRanges[] = +{ + SID_ATTR_BRUSH, SID_ATTR_BRUSH, + + // Support DrawingLayer FillStyles (no real call to below GetRanges() + // detected, still do the complete transition) + XATTR_FILL_FIRST, XATTR_FILL_LAST, + + SID_ATTR_BORDER_OUTER, SID_ATTR_BORDER_OUTER, + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER, + 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_PAGE_SHARED_FIRST, SID_ATTR_PAGE_SHARED_FIRST, + SID_ATTR_HDFT_DYNAMIC_SPACING, SID_ATTR_HDFT_DYNAMIC_SPACING, + 0 +}; + +namespace svx { + + bool ShowBorderBackgroundDlg(weld::Window* pParent, SfxItemSet* pBBSet) + { + bool bRes = false; + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr 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 SvxHeaderPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet ) +{ + return std::make_unique( pPage, pController, *rSet ); +} + +std::unique_ptr SvxFooterPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet ) +{ + return std::make_unique( 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 sal_uInt16 aWhichTab[] = { + nWSize, nWSize, + nWLRSpace, nWLRSpace, + nWULSpace, nWULSpace, + nWOn, nWOn, + nWDynamic, nWDynamic, + nWShared, nWShared, + nWSharedFirst, nWSharedFirst, + nWBrush, nWBrush, + nWBoxInfo, nWBoxInfo, + nWBox, nWBox, + nWShadow, nWShadow, + nWDynSpacing, nWDynSpacing, + + // take over DrawingLayer FillStyles + XATTR_FILL_FIRST, XATTR_FILL_LAST, // [1014 + + 0, 0}; + + const SfxItemSet& rOldSet = GetItemSet(); + SfxItemPool* pPool = rOldSet.GetPool(); + DBG_ASSERT(pPool,"no pool :-("); + MapUnit eUnit = pPool->GetMetric(nWSize); + SfxItemSet aSet(*pPool,aWhichTab); + + 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 pBoolItem(static_cast(pPool->GetDefaultItem(nWDynSpacing).Clone())); + pBoolItem->SetValue(m_xDynSpacingCB->get_active()); + aSet.Put(std::move(pBoolItem)); + } + + // Size + SvxSizeItem aSizeItem( static_cast(rOldSet.Get( nWSize )) ); + Size aSize( aSizeItem.GetSize() ); + long nDist = GetCoreValue( *m_xDistEdit, eUnit ); + 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(GetCoreValue( *m_xLMEdit, eUnit )) ); + aLR.SetRight( static_cast(GetCoreValue( *m_xRMEdit, eUnit )) ); + aSet.Put( aLR ); + + SvxULSpaceItem aUL( nWULSpace ); + if ( nId == SID_ATTR_PAGE_HEADERSET ) + aUL.SetLower( static_cast(nDist) ); + else + aUL.SetUpper( static_cast(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( 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 ) ); + + //hide "same content on first page when this is calc + bool bIsCalc = false; + const SfxPoolItem* pExt1 = GetItem(*rSet, SID_ATTR_PAGE_EXT1); + const SfxPoolItem* pExt2 = GetItem(*rSet, SID_ATTR_PAGE_EXT2); + if (dynamic_cast(pExt1) && dynamic_cast(pExt2) ) + bIsCalc = true; + m_xCntSharedFirstBox->set_visible(!bIsCalc); + + // Evaluate header-/footer- attributes + const SvxSetItem* pSetItem = nullptr; + + if ( SfxItemState::SET == rSet->GetItemState( GetWhich(nId), false, + reinterpret_cast(&pSetItem) ) ) + { + const SfxItemSet& rHeaderSet = pSetItem->GetItemSet(); + const SfxBoolItem& rHeaderOn = + static_cast(rHeaderSet.Get(GetWhich(SID_ATTR_PAGE_ON))); + + m_xTurnOnBox->set_active(rHeaderOn.GetValue()); + + if ( rHeaderOn.GetValue() ) + { + const SfxBoolItem& rDynamic = + static_cast(rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_DYNAMIC ) )); + const SfxBoolItem& rShared = + static_cast(rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SHARED ) )); + const SfxBoolItem* pSharedFirst = nullptr; + if (rHeaderSet.HasItem(GetWhich(SID_ATTR_PAGE_SHARED_FIRST))) + pSharedFirst = static_cast(&rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SHARED_FIRST ) )); + const SvxSizeItem& rSize = + static_cast(rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) )); + const SvxULSpaceItem& rUL = + static_cast(rHeaderSet.Get( GetWhich( SID_ATTR_ULSPACE ) )); + const SvxLRSpaceItem& rLR = + static_cast(rHeaderSet.Get( GetWhich( SID_ATTR_LRSPACE ) )); + if (m_xDynSpacingCB->get_visible()) + { + const SfxBoolItem& rDynSpacing = + static_cast(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 + m_xCntSharedFirstBox->hide(); + } + else + pSetItem = nullptr; + } + else + { + // defaults for distance and height + 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(); + + const SfxPoolItem* pItem = nullptr; + SfxObjectShell* pShell; + if(SfxItemState::SET == rSet->GetItemState(SID_HTML_MODE, false, &pItem) || + ( nullptr != (pShell = SfxObjectShell::Current()) && + nullptr != (pItem = pShell->GetItem(SID_HTML_MODE)))) + { + sal_uInt16 nHtmlMode = static_cast(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::ToggleButton* 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::ToggleButton&, 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 SfxItemSet( + *GetItemSet().GetPool(), + {{XATTR_FILL_FIRST, XATTR_FILL_LAST}, // DrawingLayer FillStyle definitions + {SID_COLOR_TABLE, SID_PATTERN_LIST}, // XPropertyLists for Color, Gradient, Hatch and Graphic fills + {nOuter, nOuter}, + {nInner, nInner}, + {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 SfxItemSet( + *GetItemSet().GetPool(), + {{XATTR_FILL_FIRST, XATTR_FILL_LAST}, + {nBrush, nBrush}, + {nOuter, nOuter}, + {nInner, nInner}, + {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(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 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(*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(pBBSet->Get(nWhich)); + SfxItemSet aTempSet(*pBBSet->GetPool(), + svl::Items{}); + + setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet); + aFillAttributes = + std::make_shared(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 = static_cast< const SfxBoolItem& >(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(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)); + SfxItemSet aTempSet(*rTmpSet.GetPool(), svl::Items{}); + + setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet); + aHeaderFillAttributes = std::make_shared(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 = static_cast< const SfxBoolItem& >(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(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)); + SfxItemSet aTempSet(*rTmpSet.GetPool(), svl::Items{}); + + setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet); + aFooterFillAttributes = std::make_shared(aTempSet); + } + } + + m_aBspWin.setFooterFillAttributes(aFooterFillAttributes); + } + } + + drawinglayer::attribute::SdrAllFillAttributesHelperPtr aPageFillAttributes; + + if(mbEnableDrawingLayerFillStyles) + { + // create FillAttributes directly from DrawingLayer FillStyle entries + aPageFillAttributes = std::make_shared(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)); + SfxItemSet aTempSet(*rSet.GetPool(), svl::Items{}); + + setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet); + aPageFillAttributes = std::make_shared(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(*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(*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(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(*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(&pSetItem) ) ) + { + const SfxItemSet& rHeaderSet = pSetItem->GetItemSet(); + const SfxBoolItem& rHeaderOn = + static_cast(rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_ON ) )); + + if ( rHeaderOn.GetValue() ) + { + const SvxSizeItem& rSize = static_cast( + rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) )); + const SvxULSpaceItem& rUL = static_cast( + rHeaderSet.Get( GetWhich(SID_ATTR_ULSPACE ) )); + const SvxLRSpaceItem& rLR = static_cast( + rHeaderSet.Get( GetWhich( SID_ATTR_LRSPACE ) )); + 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(&pSetItem) ) ) + { + const SfxItemSet& rFooterSet = pSetItem->GetItemSet(); + const SfxBoolItem& rFooterOn = + static_cast(rFooterSet.Get( GetWhich( SID_ATTR_PAGE_ON ) )); + + if ( rFooterOn.GetValue() ) + { + const SvxSizeItem& rSize = static_cast( + rFooterSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) )); + const SvxULSpaceItem& rUL = static_cast( + rFooterSet.Get( GetWhich( SID_ATTR_ULSPACE ) )); + const SvxLRSpaceItem& rLR = static_cast( + rFooterSet.Get( GetWhich( SID_ATTR_LRSPACE ) )); + 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( pItem) ) + { + m_aBspWin.SetTable( true ); + m_aBspWin.SetHorz( pBoolItem->GetValue() ); + } + + pItem = GetItem( rSet, SID_ATTR_PAGE_EXT2 ); + + if ( auto pBoolItem = dynamic_cast( 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() +{ + long nHHeight = m_aBspWin.GetHdHeight(); + long nHDist = m_aBspWin.GetHdDist(); + + long nFHeight = m_aBspWin.GetFtHeight(); + long nFDist = m_aBspWin.GetFtDist(); + + long nHeight = std::max(long(MINBODY), + static_cast(m_xHeightEdit->denormalize(m_xHeightEdit->get_value(FieldUnit::TWIP)))); + long nDist = m_xTurnOnBox->get_active() ? + static_cast(m_xDistEdit->denormalize(m_xDistEdit->get_value(FieldUnit::TWIP))) : 0; + + long nMin; + long nMax; + + if ( nId == SID_ATTR_PAGE_HEADERSET ) + { + nHHeight = nHeight; + nHDist = nDist; + } + else + { + nFHeight = nHeight; + nFDist = nDist; + } + + // Current values of the side edges + long nBT = m_aBspWin.GetTop(); + long nBB = m_aBspWin.GetBottom(); + long nBL = m_aBspWin.GetLeft(); + long nBR = m_aBspWin.GetRight(); + + long nH = m_aBspWin.GetSize().Height(); + 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, + 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, + long(0) ); + m_xDistEdit->set_max(m_xDistEdit->normalize(nDist), FieldUnit::TWIP); + } + + // Limit Indentation + nMax = nW - nBL - nBR - + static_cast(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(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(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..b9a4cd645 --- /dev/null +++ b/svx/source/dialog/hexcolorcontrol.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 +#include +#include +#include +#include + +namespace weld +{ +HexColorControl::HexColorControl(std::unique_ptr 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; + m_xEntry->set_text(sColor); +} + +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); + +#if 0 + if (nColor == -1) + SetControlBackground(COL_RED); + else + SetControlBackground(); +#endif + + return Color(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..1bbc40e75 --- /dev/null +++ b/svx/source/dialog/hyperdlg.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 +#include +#include +#include + + +//# # +//# 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); + + vcl::Window* pTopWindow = nullptr; + if ( !pInfo->aSize.IsEmpty() ) + { + pTopWindow = SfxGetpApp()->GetTopWindow(); + if (pTopWindow) + { + weld::Dialog* pDialog = GetController()->getDialog(); + + Size aParentSize( pTopWindow->GetSizePixel() ); + Size aDlgSize(pDialog->get_size()); + + if( aParentSize.Width() < pInfo->aPos.X() ) + pInfo->aPos.setX( aParentSize.Width()-aDlgSize.Width() < long(0.1*aParentSize.Width()) ? + long(0.1*aParentSize.Width()) : aParentSize.Width()-aDlgSize.Width() ); + if( aParentSize.Height() < pInfo->aPos. Y() ) + pInfo->aPos.setY( aParentSize.Height()-aDlgSize.Height() < long(0.1*aParentSize.Height()) ? + 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..e015b3716 --- /dev/null +++ b/svx/source/dialog/imapdlg.cxx @@ -0,0 +1,733 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "imapwnd.hxx" +#include "imapimp.hxx" +#include +#include +#include +#include "dlgunit.hxx" +#include + +#define SELF_TARGET "_self" +#define IMAP_CERN_FILTER "MAP - CERN" +#define IMAP_NCSA_FILTER "MAP - NCSA" +#define IMAP_BINARY_FILTER "SIP - StarView ImageMap" +#define IMAP_ALL_TYPE "*.*" +#define IMAP_BINARY_TYPE "*.sip" +#define IMAP_CERN_TYPE "*.map" +#define IMAP_NCSA_TYPE "*.map" + +SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID( SvxIMapDlgChildWindow, SID_IMAP ); + +// ControllerItem + +SvxIMapDlgItem::SvxIMapDlgItem( SvxIMapDlg& rIMapDlg, SfxBindings& rBindings ) : + SfxControllerItem ( SID_IMAP_EXEC, rBindings ), + rIMap ( rIMapDlg ) +{ +} + +void SvxIMapDlgItem::StateChanged( sal_uInt16 nSID, SfxItemState /*eState*/, + const SfxPoolItem* pItem ) +{ + if ( ( nSID == SID_IMAP_EXEC ) && pItem ) + { + const SfxBoolItem* pStateItem = dynamic_cast( 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(pBindings, this, _pParent->GetFrameWeld())); + SvxIMapDlg* pDlg = static_cast(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() ); + 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 xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querymodifyimagemapchangesdialog.ui")); + std::unique_ptr xQBox(xBuilder->weld_message_dialog("QueryModifyImageMapChangesDialog")); + const 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 xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querysaveimagemapchangesdialog.ui")); + std::unique_ptr xQBox(xBuilder->weld_message_dialog("QuerySaveImageMapChangesDialog")); + const 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 ) +{ + TargetList aNewList( rTargetList ); + + m_xIMapWnd->SetTargetList( aNewList ); + + m_xCbbTarget->clear(); + + for (const OUString & s : aNewList) + 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 + pOwnData->aUpdateTargetList.clear(); + + // 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 ) + { + TargetList aTargetList( *pTargetList ); + + for (const OUString & s : aTargetList) + pOwnData->aUpdateTargetList.push_back( s ); + } + + 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( OBJ_RECT ); + } + else if (rNewItemId == "TBI_CIRCLE") + { + SetActiveTool( rNewItemId ); + m_xIMapWnd->SetObjKind( OBJ_CIRC ); + } + else if (rNewItemId == "TBI_POLY") + { + SetActiveTool( rNewItemId ); + m_xIMapWnd->SetObjKind( OBJ_POLY ); + } + else if (rNewItemId == "TBI_FREEPOLY") + { + SetActiveTool( rNewItemId ); + m_xIMapWnd->SetObjKind( OBJ_FREEFILL ); + } + 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.SetDisplayDirectory( SvtPathOptions().GetWorkPath() ); + + if( aDlg.Execute() == ERRCODE_NONE ) + { + INetURLObject aURL( aDlg.GetPath() ); + DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" ); + std::unique_ptr pIStm(::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ )); + + if( pIStm ) + { + aLoadIMap.Read( *pIStm, IMAP_FORMAT_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.SetDisplayDirectory( SvtPathOptions().GetWorkPath() ); + + if( aDlg.Execute() == ERRCODE_NONE ) + { + const OUString aFilter( aDlg.GetCurrentFilter() ); + OUString aExt; + sal_uIntPtr nFormat; + + if ( aFilter == aBinFilter ) + { + nFormat = IMAP_FORMAT_BIN; + aExt = "sip"; + } + else if ( aFilter == aCERNFilter ) + { + nFormat = IMAP_FORMAT_CERN; + aExt = "map"; + } + else if ( aFilter == aNCSAFilter ) + { + nFormat = IMAP_FORMAT_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 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(const OString& 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 xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querysaveimagemapchangesdialog.ui")); + std::unique_ptr 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( 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(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..f2a10e45e --- /dev/null +++ b/svx/source/dialog/imapimp.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_DIALOG_IMAPIMP_HXX +#define INCLUDED_SVX_SOURCE_DIALOG_IMAPIMP_HXX + +#include +#include +#include +#include + +class IMapOwnData +{ +public: + + Idle aIdle; + Graphic aUpdateGraphic; + ImageMap aUpdateImageMap; + TargetList aUpdateTargetList; + void* pUpdateEditingObject; + bool bExecState; + + 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..2caa529e1 --- /dev/null +++ b/svx/source/dialog/imapwnd.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 +#include +#include +#include +#include +#include +#include + +#include +#include "imapwnd.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +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() +{ + SfxItemPool::Free(pIMapPool); +} + +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(); + IMapObject* pIMapObj; + + if ( pSdrObj ) + { + 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( pPage->GetObj( i )->GetUserData( 0 ) )->GetObject() ) ); + } + } + + pModel->SetChanged( false ); + } + + return aIMap; +} + +void IMapWindow::SetTargetList( TargetList& rTargetList ) +{ + // Delete old List + aTargetList.clear(); + + // Fill with the provided list + for(const OUString & s : rTargetList) + aTargetList.push_back( s ); + + pModel->SetChanged( false ); +} + +SdrObject* IMapWindow::CreateObj( const IMapObject* pIMapObj ) +{ + tools::Rectangle aClipRect( Point(), GetGraphicSize() ); + SdrObject* pSdrObj = nullptr; + IMapObjectPtr pCloneIMapObj; + + switch( pIMapObj->GetType() ) + { + case IMAP_OBJ_RECTANGLE: + { + const IMapRectangleObject* pIMapRectObj = static_cast(pIMapObj); + tools::Rectangle aDrawRect( pIMapRectObj->GetRectangle( false ) ); + + // clipped on CanvasPane + aDrawRect.Intersection( aClipRect ); + + pSdrObj = new SdrRectObj(*pModel, aDrawRect); + pCloneIMapObj.reset(static_cast(new IMapRectangleObject( *pIMapRectObj ))); + } + break; + + case IMAP_OBJ_CIRCLE: + { + const IMapCircleObject* pIMapCircleObj = static_cast(pIMapObj); + const Point aCenter( pIMapCircleObj->GetCenter( false ) ); + const 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, + 36000); + pCloneIMapObj.reset(static_cast(new IMapCircleObject( *pIMapCircleObj ))); + } + break; + + case IMAP_OBJ_POLYGON: + { + const IMapPolygonObject* pIMapPolyObj = static_cast(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, + 36000); + } + 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, + OBJ_POLY, + basegfx::B2DPolyPolygon(aPolygon)); + } + + pCloneIMapObj.reset(static_cast(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(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 OBJ_RECT: + { + SdrRectObj* pRectObj = const_cast(static_cast(&rObj)); + auto pObj = std::make_shared( pRectObj->GetLogicRect(), "", "", "", "", "", true, false ); + + pRectObj->AppendUserData( std::unique_ptr(new IMapUserData( pObj )) ); + } + break; + + case OBJ_CIRC: + { + SdrCircObj* pCircObj = const_cast( static_cast(&rObj) ); + SdrPathObj* pPathObj = static_cast( 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( aPoly, "", "", "", "", "", true, false ); + pObj->SetExtraEllipse( aPoly.GetBoundRect() ); + pCircObj->AppendUserData( std::unique_ptr(new IMapUserData( pObj )) ); + } + break; + + case OBJ_POLY: + case OBJ_FREEFILL: + case OBJ_PATHPOLY: + case OBJ_PATHFILL: + { + SdrPathObj* pPathObj = const_cast( static_cast(&rObj) ); + const basegfx::B2DPolyPolygon& rXPolyPoly = pPathObj->GetPathPoly(); + + if ( rXPolyPoly.count() ) + { + tools::Polygon aPoly(rXPolyPoly.getB2DPolygon(0)); + auto pObj = std::make_shared( aPoly, "", "", "", "", "", true, false ); + pPathObj->AppendUserData( std::unique_ptr(new IMapUserData( pObj )) ); + } + } + break; + + default: + break; + } +} + +void IMapWindow::SdrObjChanged( const SdrObject& rObj ) +{ + IMapUserData* pUserData = static_cast( rObj.GetUserData( 0 ) ); + + if ( pUserData ) + { + 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 OBJ_RECT: + { + pUserData->ReplaceObject( std::make_shared( static_cast(rObj).GetLogicRect(), + aURL, aAltText, aDesc, aTarget, "", bActive, false ) ); + } + break; + + case OBJ_CIRC: + { + const SdrCircObj& rCircObj = static_cast(rObj); + SdrPathObj* pPathObj = static_cast( rCircObj.ConvertToPolyObj( false, false ).release() ); + tools::Polygon aPoly(pPathObj->GetPathPoly().getB2DPolygon(0)); + + auto pObj = std::make_shared( 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 OBJ_POLY: + case OBJ_FREEFILL: + case OBJ_PATHPOLY: + case OBJ_PATHFILL: + { + const SdrPathObj& rPathObj = static_cast(rObj); + const basegfx::B2DPolyPolygon& rXPolyPoly = rPathObj.GetPathPoly(); + + if ( rXPolyPoly.count() ) + { + tools::Polygon aPoly(rPathObj.GetPathPoly().getB2DPolygon(0)); + auto pObj = std::make_shared( 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() ).IsInside( 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( 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 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)) + { + const OUString aString; + INetBookmark aBookMark( aString, aString ); + 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 ) + { + 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() ) + { + 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; + + SfxItemSet aSet( *pIMapPool, svl::Items{} ); + + 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 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 ) + { + IMapObject* pIMapObj = GetIMapObj( pSdrObj ); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr aDlg(pFact->CreateURLDialog(GetDrawingArea(), pIMapObj->GetURL(), pIMapObj->GetAltText(), pIMapObj->GetDesc(), + pIMapObj->GetTarget(), pIMapObj->GetName(), aTargetList)); + if ( aDlg->Execute() == RET_OK ) + { + 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..62a49188e --- /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 +#include +#include +#include +#include +#include + +#include + +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 Clone( SdrObject * ) const override { return std::unique_ptr(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 aInfoLink; + SfxItemPool* pIMapPool; + SfxItemInfo maItemInfos[1] = {}; + css::uno::Reference< css::frame::XFrame > + mxDocumentFrame; + std::unique_ptr mxDropTargetHelper; + std::unique_ptr 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& rLink ) { aInfoLink = rLink; } + + void SetTargetList( 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..5b7526d94 --- /dev/null +++ b/svx/source/dialog/langbox.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::linguistic2; +using namespace ::com::sun::star::uno; + +OUString GetDicInfoStr( const OUString& 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 && + !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(eLangType))); +} + +void SvxLanguageBox::set_id(int pos, const LanguageType eLangType) +{ + m_xControl->set_id(pos, OUString::number(static_cast(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(eLangType))); +} + +void SvxLanguageBox::append(const LanguageType eLangType, const OUString& rStr) +{ + m_xControl->append(OUString::number(static_cast(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& 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 ); + } + if (bAddAvailable) + { + aTmp = xAvail->getAvailableLocales( SN_HYPHENATOR ); + aHyphAvailLang = lcl_LocaleSeqToLangSeq( aTmp ); + } + if (bAddAvailable) + { + 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 aKnown; + sal_uInt32 nCount; + if ( nLangList & SvxLanguageListFlags::ONLY_KNOWN ) + { + aKnown = LocaleDataWrapper::getInstalledLanguageTypes(); + nCount = aKnown.size(); + } + else + { + nCount = SvtLanguageTable::GetLanguageEntryCount(); + } + + std::vector 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(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(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(); + aStrEntry += " - " + SvtLanguageTable::GetLanguageString( nRealLang ); + } + + if (m_bWithCheckmark) + { + if (!m_xSpellUsedLang) + { + Reference xSpell = LinguMgr::GetSpellChecker(); + if (xSpell.is()) + m_xSpellUsedLang.reset(new Sequence(xSpell->getLanguages())); + } + + bool bFound = m_xSpellUsedLang && lcl_SeqHasLang(*m_xSpellUsedLang, static_cast(nRealLang)); + + return weld::ComboBoxEntry(aStrEntry, OUString::number(static_cast(nLangType)), bFound ? OUString(RID_SVXBMP_CHECKED) : OUString(RID_SVXBMP_NOTCHECKED)); + } + else + return weld::ComboBoxEntry(aStrEntry, OUString::number(static_cast(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 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..7df6f472f --- /dev/null +++ b/svx/source/dialog/linkwarn.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 +#include +#include + +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 + SvtMiscOptions aMiscOpt; + m_xWarningOnBox->set_active(aMiscOpt.ShowLinkWarningDialog()); + m_xWarningOnBox->set_sensitive(!aMiscOpt.IsShowLinkWarningDialogReadOnly()); +} + +SvxLinkWarningDialog::~SvxLinkWarningDialog() +{ + try + { + // save value of "warning off" checkbox, if necessary + SvtMiscOptions aMiscOpt; + bool bChecked = m_xWarningOnBox->get_active(); + if (aMiscOpt.ShowLinkWarningDialog() != bChecked) + aMiscOpt.SetShowLinkWarningDialog(bChecked); + } + 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..fd237aea3 --- /dev/null +++ b/svx/source/dialog/measctrl.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 +#include +#include +#include +#include +#include +#include +#include +#include + +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(PushFlags::MAPMODE); + + rRefDevice.SetMapMode(m_aMapMode); + + Size aSize = rRefDevice.PixelToLogic(rSize); + Point aPt1(aSize.Width() / 5, static_cast(aSize.Height() / 2)); + pMeasureObj->SetPoint(aPt1, 0); + Point aPt2(aSize.Width() * 4 / 5, static_cast(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(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 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(PushFlags::MAPMODE); + rRefDevice.SetMapMode(m_aMapMode); + Size aOutSize(rRefDevice.PixelToLogic(GetOutputSizePixel())); + rRefDevice.Pop(); + + Point aPt(m_aMapMode.GetOrigin()); + long nX = long((double(aOutSize.Width()) - (double(aOutSize.Width()) * double(*pMultFrac))) / 2.0 + 0.5); + long nY = 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..9cf4926bf --- /dev/null +++ b/svx/source/dialog/optgrid.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 +#include + +#include +#include +#include + +// local functions +static void lcl_GetMinMax(weld::MetricSpinButton const& rField, int& nMin, int& nMax) +{ + rField.get_range(nMin, nMax, FieldUnit::TWIP); + nMin = rField.denormalize(nMin); + nMax = rField.denormalize(nMax); +} + +static void lcl_SetMinMax(weld::MetricSpinButton& rField, int nMin, int 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(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 ); + int 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 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 SvxGridTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet) +{ + return std::make_unique(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( GetWhich( SID_ATTR_GRID_OPTIONS ) ); + long nX = GetCoreValue( *m_xMtrFldDrawX, eUnit ); + long nY = GetCoreValue( *m_xMtrFldDrawY, eUnit ); + + aGridItem.nFldDrawX = static_cast(nX); + aGridItem.nFldDrawY = static_cast(nY); + aGridItem.nFldDivisionX = static_cast(m_xNumFldDivisionX->get_value() - 1); + aGridItem.nFldDivisionY = static_cast(m_xNumFldDivisionY->get_value() - 1); + + rCoreSet->Put( aGridItem ); + } + return bAttrModified; +} + +void SvxGridTabPage::Reset( const SfxItemSet* rSet ) +{ + const SfxPoolItem* pAttr = nullptr; + + if( SfxItemState::SET == rSet->GetItemState( SID_ATTR_GRID_OPTIONS , false, + &pAttr )) + { + const SvxGridItem* pGridAttr = static_cast(pAttr); + m_xCbxUseGridsnap->set_active(pGridAttr->bUseGridsnap); + m_xCbxSynchronize->set_active(pGridAttr->bSynchronize); + m_xCbxGridVisible->set_active(pGridAttr->bGridVisible); + + MapUnit eUnit = + rSet->GetPool()->GetMetric( GetWhich( 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 SfxPoolItem* pAttr = nullptr; + if( SfxItemState::SET == rSet.GetItemState( SID_ATTR_GRID_OPTIONS , false, + &pAttr )) + { + const SvxGridItem* pGridAttr = static_cast(pAttr); + 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 + if( SfxItemState::SET == rSet.GetItemState( SID_ATTR_METRIC , false, + &pAttr )) + { + const SfxUInt16Item* pItem = static_cast(pAttr); + + FieldUnit eFUnit = static_cast(static_cast(pItem->GetValue())); + + if (eFUnit != m_xMtrFldDrawX->get_unit()) + { + // Set Metrics + int 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::ToggleButton&, 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::ToggleButton&, 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..6dc8e72f0 --- /dev/null +++ b/svx/source/dialog/page.hrc @@ -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 . + */ + +#ifndef INCLUDED_SVX_SOURCE_DIALOG_PAGE_HRC +#define INCLUDED_SVX_SOURCE_DIALOG_PAGE_HRC + +#include +#include + +#define NC_(Context, String) reinterpret_cast(Context "\004" u8##String) + +const std::pair 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 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", "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..f7eae17db --- /dev/null +++ b/svx/source/dialog/pagectrl.cxx @@ -0,0 +1,406 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CELL_WIDTH 1600L +#define CELL_HEIGHT 800L + +SvxPageWindow::SvxPageWindow() : + aWinSize(), + aSize(), + 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), + maHeaderFillAttributes(), + maFooterFillAttributes(), + maPageFillAttributes(), + 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(PushFlags::MAPMODE); + rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip)); + + Fraction aXScale(aWinSize.Width(), std::max(long(aSize.Width() * 2 + aSize.Width() / 8), 1L)); + Fraction aYScale(aWinSize.Height(), std::max(aSize.Height(), 1L)); + 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())); + 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; + 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)); + + long nL = nLeft; + 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; + 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)); + long nHDiff = 0; + 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) + { + // Paint Table, if necessary center it + rRenderContext.SetLineColor(COL_LIGHTGRAY); + + long nW = aRect.GetWidth(); + long nH = aRect.GetHeight(); + long const nTW = CELL_WIDTH * 3; + long const nTH = CELL_HEIGHT * 3; + long _nLeft = bHorz ? aRect.Left() + ((nW - nTW) / 2) : aRect.Left(); + 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())) + { + 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()) + { + const drawinglayer::geometry::ViewInformation2D aViewInformation2D( + basegfx::B2DHomMatrix(), rRenderContext.GetViewTransformation(), aPaintRange, nullptr, + 0.0, css::uno::Sequence()); + + std::unique_ptr pProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice(rRenderContext, aViewInformation2D)); + if (pProcessor) + { + 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(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 +#include +#include +#include +#include + +SvxPageNumberListBox::SvxPageNumberListBox(std::unique_ptr 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..f746a023c --- /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 +#include +#include "page.hrc" + +SvxPaperSizeListBox::SvxPaperSizeListBox(std::unique_ptr pControl) + : m_xControl(std::move(pControl)) +{ + m_xControl->set_size_request(150, -1); +} + +void SvxPaperSizeListBox::FillPaperSizeEntries( PaperSizeApp eApp ) +{ + const std::pair* 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(pPaperAry[i].second); + m_xControl->append(OUString::number(static_cast(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(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(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..fb5003559 --- /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 +#include +#include +#include + +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(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(); + + 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) + { + long nLeft = nLeftMargin * aLineSiz.Width() / aSize.Width(); + long nFirst = nFirstLineOffset * aLineSiz.Width() / aSize.Width(); + long nTmp = nLeft + nFirst; + + if (i == 3) + { + aPnt.AdjustX(nTmp ); + aSiz.AdjustWidth( -nTmp ); + } + else + { + aPnt.AdjustX(nLeft ); + aSiz.AdjustWidth( -nLeft ); + } + 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) + { + long nLW = 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 +#include +#include +#include +#include + +IMPL_LINK_NOARG(SvxPasswordDialog, ButtonHdl, weld::Button&, void) +{ + bool bOK = true; + + if (m_xNewPasswdED->get_text() != m_xRepeatPasswdED->get_text()) + { + std::unique_ptr 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 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..80340a168 --- /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 + +SvxRelativeField::SvxRelativeField(std::unique_ptr 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) + { + 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..f5309e843 --- /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 +#include +#include + +#include + +#include +#include +#include +#include +#include "rlrcitem.hxx" +#include +#include + +SvxRulerItem::SvxRulerItem(sal_uInt16 _nId, SvxRuler &rRul, SfxBindings &rBindings) +: SfxControllerItem(_nId, rBindings), + rRuler(rRul) +{ +} + + +void SvxRulerItem::StateChanged( 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( pState ); + rRuler.UpdateFrameMinMax(pItem); + break; + } + case SID_ATTR_LONG_LRSPACE: + { + const SvxLongLRSpaceItem *pItem = dynamic_cast( 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( 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( 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( 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( 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( 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( 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( 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( pState ); + SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxLRSpaceItem expected"); + rRuler.UpdateParaBorder(); + } + break; + case SID_RULER_TEXT_RIGHT_TO_LEFT : + { + const SfxBoolItem *pItem = dynamic_cast( 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..574d7fe91 --- /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 + +class SvxRuler; + +class SvxRulerItem : public SfxControllerItem +{ +private: + SvxRuler& rRuler; + +protected: + virtual void StateChanged( 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..4a73ad663 --- /dev/null +++ b/svx/source/dialog/rubydialog.cxx @@ -0,0 +1,890 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +{ + +static const char cRubyBaseText[] = "RubyBaseText"; +static const char cRubyText[] = "RubyText"; +static const char cRubyAdjust[] = "RubyAdjust"; +static const char cRubyPosition[] = "RubyPosition"; +static const char cRubyCharStyleName[] = "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(pBindings, this, _pParent->GetFrameWeld()); + SetController(xDlg); + xDlg->Initialize(pInfo); +} + +SfxChildWinInfo SvxRubyChildWindow::GetInfo() const +{ + return SfxChildWindow::GetInfo(); +} + +class SvxRubyData_Impl : public cppu::WeakImplHelper +{ + Reference xModel; + Reference xSelection; + Sequence aRubyValues; + Reference xController; + bool bHasSelectionChanged; + +public: + SvxRubyData_Impl(); + virtual ~SvxRubyData_Impl() override; + + void SetController(const Reference& xCtrl); + Reference const & GetModel() + { + if (!xController.is()) + xModel = nullptr; + else + xModel = xController->getModel(); + return xModel; + } + bool HasSelectionChanged() const + { + return bHasSelectionChanged; + } + Reference 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& 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) +{ +} + +SvxRubyData_Impl::~SvxRubyData_Impl() +{ +} + +void SvxRubyData_Impl::SetController(const Reference& xCtrl) +{ + if (xCtrl.get() != xController.get()) + { + try + { + Reference 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 xSelSupp(xController, UNO_QUERY); + if (xSelSupp.is()) + xSelSupp->removeSelectionChangeListener(this); + } + catch (const Exception&) + { + } + xController = nullptr; +} + +void SvxRubyData_Impl::AssertOneEntry() +{ + //create one entry + if (!aRubyValues.hasElements()) + { + aRubyValues.realloc(1); + Sequence& 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")) + , 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("cancel")) + , 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_user_managed_scrolling(); + 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 aScrLk(LINK(this, SvxRubyDialog, ScrollHdl_Impl)); + m_xScrolledWindow->connect_vadjustment_changed(aScrLk); + + Link aEditLk(LINK(this, SvxRubyDialog, EditModifyHdl_Impl)); + Link aFocusLk(LINK(this, SvxRubyDialog, EditFocusHdl_Impl)); + Link aKeyUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownHdl_Impl)); + Link 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(); + //get selection from current view frame + SfxViewFrame* pCurFrm = SfxViewFrame::Current(); + Reference< XController > xCtrl = pCurFrm->GetFrame().GetController(); + m_pImpl->SetController(xCtrl); + if (m_pImpl->HasSelectionChanged()) + { + + 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 xSupplier(xModel, UNO_QUERY); + if (xSupplier.is()) + { + try + { + Reference xFam = xSupplier->getStyleFamilies(); + Any aChar = xFam->getByName("CharacterStyles"); + Reference xChar; + aChar >>= xChar; + Reference 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; + aStyle >>= xStyle; + Reference xPrSet(xStyle, UNO_QUERY); + OUString sName, sCoreName; + if (xPrSet.is()) + { + Reference 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&) + { + OSL_FAIL("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& aRubyValues = m_pImpl->GetRubyValues(); + bool bEnable = aRubyValues.getLength() > nPos; + if (bEnable) + { + const Sequence 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() +{ + long nTempLastPos = GetLastPos(); + 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())) + { + Sequence& aRubyValues = m_pImpl->GetRubyValues(); + DBG_ASSERT(aRubyValues.getLength() > (i / 2 + nTempLastPos), "wrong index" ); + SetModified(true); + Sequence& rProps = aRubyValues.getArray()[i / 2 + nTempLastPos]; + for (PropertyValue & propVal : rProps) + { + 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& 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 &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& 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 xSelection = m_pImpl->GetRubySelection(); + if (IsModified() && xSelection.is()) + { + try + { + xSelection->setRubyList(aRubyValues, false); + } + catch (const Exception&) + { + OSL_FAIL("Exception caught"); + } + } +} + +IMPL_LINK_NOARG(SvxRubyDialog, CloseHdl_Impl, weld::Button&, void) +{ + Close(); +} + +IMPL_LINK_NOARG(SvxRubyDialog, StylistHdl_Impl, weld::Button&, void) +{ + std::unique_ptr pState; + SfxItemState eState = pBindings->QueryState(SID_STYLE_DESIGNER, pState); + if (eState <= SfxItemState::SET || !pState || !static_cast(pState.get())->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(); + Sequence& aRubyValues = m_pImpl->GetRubyValues(); + for (PropertyValues & rProps : aRubyValues) + { + for (PropertyValue & propVal : 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(); + Sequence& aRubyValues = m_pImpl->GetRubyValues(); + for (PropertyValues & rProps : aRubyValues) + { + for (PropertyValue & propVal : 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(); + Sequence& aRubyValues = m_pImpl->GetRubyValues(); + for (PropertyValues & rProps : aRubyValues) + { + for (PropertyValue & propVal : 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(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); + + long nTextHeight = rRenderContext.GetTextHeight(); + long nBaseWidth = rRenderContext.GetTextWidth(sBaseText); + + vcl::Font aRubyFont(aFont); + aRubyFont.SetFontHeight(aRubyFont.GetFontHeight() * 70 / 100); + rRenderContext.SetFont(aRubyFont); + long nRubyWidth = rRenderContext.GetTextWidth(sRubyText); + rRenderContext.SetFont(aFont); + + RubyAdjust nAdjust = static_cast(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; + + long nCenter = aWinSize.Width() / 2; + long nHalfWidth = std::max( nBaseWidth, nRubyWidth ) /2; + long nLeftStart = nCenter - nHalfWidth; + long nRightEnd = nCenter + nHalfWidth; + + // Default values for TOP or no selection + long nYRuby = aWinSize.Height() / 4 - nTextHeight / 2; + long nYBase = aWinSize.Height() * 3 / 4 - nTextHeight / 2; + + sal_Int16 nRubyPos = m_pParentDlg->m_xPositionLB->get_active(); + if ( nRubyPos == 1 ) // BOTTOM + { + 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); + } + + long nYOutput; + 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: + { + 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(); + 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); + 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..eb2a0f7a6 --- /dev/null +++ b/svx/source/dialog/rulritem.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(rCmp).mlLeft && + mlRight == static_cast(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 ? convertMm100ToTwip(aLeftRightMargin.Left) : aLeftRightMargin.Left; + mlRight = bConvert ? convertMm100ToTwip(aLeftRightMargin.Right) : aLeftRightMargin.Right; + return true; + } + } + else if ( rVal >>= nVal ) + { + if ( bConvert ) + nVal = convertMm100ToTwip( nVal ); + + 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(long lLeft, long lRight, sal_uInt16 nId) : + SfxPoolItem (nId), + mlLeft (lLeft), + mlRight (lRight) +{} + +SvxLongLRSpaceItem::SvxLongLRSpaceItem() : + SfxPoolItem (0), + mlLeft (0), + mlRight (0) +{} + +void SvxLongLRSpaceItem::SetLeft(long lArgLeft) +{ + mlLeft = lArgLeft; +} + +void SvxLongLRSpaceItem::SetRight(long lArgRight) +{ + mlRight = lArgRight; +} + +/* SvxLongULSpaceItem */ + +bool SvxLongULSpaceItem::operator==( const SfxPoolItem& rCmp) const +{ + return SfxPoolItem::operator==(rCmp) && + mlLeft == static_cast(rCmp).mlLeft && + mlRight == static_cast(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 ? convertMm100ToTwip( aUpperLowerMargin.Upper ) : aUpperLowerMargin.Upper; + mlRight = bConvert ? convertMm100ToTwip( aUpperLowerMargin.Lower ) : aUpperLowerMargin.Lower; + return true; + } + } + else if ( rVal >>= nVal ) + { + if ( bConvert ) + nVal = convertMm100ToTwip( nVal ); + + 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(long lLeft, long lRight, sal_uInt16 nId) : + SfxPoolItem (nId), + mlLeft (lLeft), + mlRight (lRight) +{} + +SvxLongULSpaceItem::SvxLongULSpaceItem() : + SfxPoolItem (0), + mlLeft (0), + mlRight (0) +{} + + +void SvxLongULSpaceItem::SetUpper(long lArgLeft) +{ + mlLeft = lArgLeft; +} + +void SvxLongULSpaceItem::SetLower(long lArgRight) +{ + mlRight = lArgRight; +} + +/* SvxPagePosSizeItem */ + +bool SvxPagePosSizeItem::operator==( const SfxPoolItem& rCmp) const +{ + return SfxPoolItem::operator==(rCmp) && + aPos == static_cast(rCmp).aPos && + lWidth == static_cast(rCmp).lWidth && + lHeight == static_cast(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, long lW, 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(rCmp).nActColumn || + nLeft != static_cast(rCmp).nLeft || + nRight != static_cast(rCmp).nRight || + bTable != static_cast(rCmp).bTable || + Count() != static_cast(rCmp).Count()) + return false; + + const sal_uInt16 nCount = static_cast(rCmp).Count(); + for(sal_uInt16 i = 0; i < nCount;++i) + { + if( (*this)[i] != static_cast(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; + + 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(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(nVal); + break; + case MID_ACTUAL: + rVal >>= nVal; + nActColumn = static_cast(nVal); + break; + case MID_TABLE: + rVal >>= nVal; + bTable = static_cast(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(long left) +{ + nLeft = left; +} + +void SvxColumnItem::SetRight(long right) +{ + nRight = right; +} + + +bool SvxColumnItem::IsFirstAct() const +{ + return nActColumn == 0; +} + +bool SvxColumnItem::IsLastAct() const +{ + return nActColumn == Count() - 1; +} + +SvxColumnDescription::SvxColumnDescription(long start, long end, bool bVis) : + nStart (start), + nEnd (end), + bVisible (bVis), + nEndMin (0), + nEndMax (0) +{} + +SvxColumnDescription::SvxColumnDescription(long start, long end, long endMin, long endMax, bool bVis) : + nStart (start), + nEnd (end), + bVisible (bVis), + // fdo#85858 hack: clamp these to smaller value to prevent overflow + nEndMin(std::min(endMin, std::numeric_limits::max())), + nEndMax(std::min(endMax, std::numeric_limits::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); +} + +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(rCmp).nStartX && + nEndX == static_cast(rCmp).nEndX && + nStartY == static_cast(rCmp).nStartY && + nEndY == static_cast(rCmp).nEndY && + bLimits == static_cast(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( long nSX, long nEX, + long nSY, 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(long lValue) +{ + nStartX = lValue; +} + +void SvxObjectItem::SetEndX(long lValue) +{ + nEndX = lValue; +} + +void SvxObjectItem::SetStartY(long lValue) +{ + nStartY = lValue; +} + +void SvxObjectItem::SetEndY(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 +#include +#include + +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..1cdb3cfc0 --- /dev/null +++ b/svx/source/dialog/searchcharmap.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 +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + + +SvxSearchCharSet::SvxSearchCharSet(std::unique_ptr pScrolledWindow, const VclPtr& 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& 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()); + + int i; + 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)); + } + 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 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::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::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; + + //scrollbar settings -- error + int nLastRow = (nCount - 1 + COLUMN_COUNT) / COLUMN_COUNT; + mxScrollArea->vadjustment_configure(mxScrollArea->vadjustment_get_value(), 0, nLastRow, 1, ROW_COUNT - 1, ROW_COUNT); + + // 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::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() ) + { + OSL_ENSURE(m_xAccessible.is(), "Who wants to create a child of my table without a parent?"); + auto xItem = std::make_shared(*this, + m_xAccessible.get(), sal::static_int_cast< sal_uInt16 >(_nPos)); + aFind = m_aItems.emplace(_nPos, xItem).first; + OUStringBuffer buf; + std::unordered_map::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/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 +#include +#include +#include +#include +#include + +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..28747acd7 --- /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 +#include + +#include + +#include "srchctrl.hxx" +#include +#include + +SvxSearchController::SvxSearchController +( + sal_uInt16 _nId, + SfxBindings& rBind, + SvxSearchDialog& rDlg +) : + SfxControllerItem( _nId, rBind ), + + rSrchDlg( rDlg ) +{ +} + + +void SvxSearchController::StateChanged( 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(pState) != nullptr, "wrong item type" ); + SearchOptionFlags nFlags = static_cast(static_cast(pState)->GetValue()); + rSrchDlg.EnableControls_Impl( nFlags ); + } + else if ( SID_SEARCH_ITEM == nSID ) + { + DBG_ASSERT( dynamic_cast( pState) != nullptr, "wrong item type" ); + rSrchDlg.SetItem_Impl( static_cast(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..96fe59b66 --- /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 +class SvxSearchDialog; + +class SvxSearchController : public SfxControllerItem +{ + SvxSearchDialog& rSrchDlg; + +protected: + virtual void StateChanged( 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..6653be858 --- /dev/null +++ b/svx/source/dialog/srchdlg.cxx @@ -0,0 +1,2452 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include "srchctrl.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +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; + +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 : is_typed_flags {}; +} + +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; + std::unique_ptr pRanges; + Timer 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& rStrLst, weld::ComboBox& rCBox, sal_uInt16 nRememberSize) +{ + const SfxStringListItem* pSrchItem = + static_cast(SfxGetpApp()->GetItem( nId )); + + if (pSrchItem) + { + std::vector 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& rStrLst ) +{ + DBG_ASSERT( !rStrLst.empty(), "check in advance"); + SfxGetpApp()->PutItem( SfxStringListItem( nId, &rStrLst ) ); +} + +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(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, + "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(); +} + +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( rBindings.GetDispatcher()->Execute( FID_SEARCH_SEARCHSET, SfxCallMode::SLOT, ppArgs ) ); + + if ( pSrchSetItem ) + InitAttrList_Impl( &pSrchSetItem->GetItemSet(), nullptr ); + + const SvxSetItem* pReplSetItem = + static_cast( 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(); + + + SvtCJKOptions aCJKOptions; + if(!aCJKOptions.IsJapaneseFindEnabled()) + { + m_xJapOptionsCB->set_active( false ); + m_xJapOptionsCB->hide(); + m_xJapOptionsBtn->hide(); + } + if(!aCJKOptions.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); + OUString sTarget("_self"); + + bool bSearchComponent1 = false; + bool bSearchComponent2 = false; + if(xDispatchProv.is()) + { + 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 ) + { + 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(); +} + +void SvxSearchDialog::Activate() +{ + // apply possible transliteration changes of the SvxSearchItem member + DBG_ASSERT( pSearchItem, "SearchItem missing" ); + 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 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 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 ); + + aLink2 = LINK( this, SvxSearchDialog, FlagHdl_Impl ); + m_xReplaceBackwardsCB->connect_clicked( aLink2 ); + m_xWordBtn->connect_clicked( aLink2 ); + m_xSelectionBtn->connect_clicked( aLink2 ); + m_xMatchCaseCB->connect_clicked( aLink2 ); + m_xRegExpBtn->connect_clicked( aLink2 ); + m_xWildcardBtn->connect_clicked( aLink2 ); + m_xNotesBtn->connect_clicked( aLink2 ); + m_xSimilarityBox->connect_clicked( aLink2 ); + m_xJapOptionsCB->connect_clicked( aLink2 ); + m_xJapMatchFullHalfWidthCB->connect_clicked( aLink2 ); + m_xIncludeDiacritics->connect_clicked( aLink2 ); + m_xIncludeKashida->connect_clicked( aLink2 ); + m_xLayoutBtn->connect_clicked( 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" ); + + SvtCJKOptions aCJKOptions; + 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(aCJKOptions.IsCJKFontEnabled()); + m_xJapOptionsCB->set_visible(aCJKOptions.IsJapaneseFindEnabled()); + m_xJapOptionsBtn->set_visible(aCJKOptions.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() ); + if ( SvxSearchDialog::IsOtherOptionsExpanded() ) + m_xOtherOptionsExpander->set_expanded( true ); + ApplyTransliterationFlags_Impl( pSearchItem->GetTransliterationFlags() ); + + ShowOptionalControls_Impl(); + + if ( pSearchItem->GetAppFlag() == SvxSearchApp::CALC ) + { + m_xCalcGrid->show(); + m_xSearchFormattedCB->set_active( aOpt.IsSearchFormatted() ); + Link aLink = LINK( this, SvxSearchDialog, FlagHdl_Impl ); + m_xCalcSearchInLB->connect_changed( LINK( this, SvxSearchDialog, LBSelectHdl_Impl ) ); + m_xRowsBtn->connect_clicked( aLink ); + m_xColumnsBtn->connect_clicked( aLink ); + m_xAllSheetsCB->connect_clicked( aLink ); + m_xSearchFormattedCB->connect_clicked( 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(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(rBindings.GetDispatcher()->Execute( FID_SEARCH_SEARCHSET, SfxCallMode::SLOT, ppArgs )); + + if ( pSrchSetItem ) + InitAttrList_Impl( &pSrchSetItem->GetItemSet(), nullptr ); + + const SvxSetItem* pReplSetItem = + static_cast( 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 && pSSet ) + { + const sal_uInt16* pPtr = pSSet->GetRanges(); + const sal_uInt16* pTmp = pPtr; + + while( *pPtr ) + { + pPtr += 2; + } + sal_sSize nCnt = pPtr - pTmp + 1; + pImpl->pRanges.reset( new sal_uInt16[nCnt] ); + memcpy( pImpl->pRanges.get(), pTmp, sizeof(sal_uInt16) * nCnt ); + } + + 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::Button&, 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(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 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 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()) + { + 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::Button&, 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* 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() ) ); +} + +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(*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 ) + return; + + SfxItemPool& rPool = pSh->GetPool(); + SfxItemSet aSet(rPool, pImpl->pRanges.get()); + + 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 pDlg(pFact->CreateTabItemDialog(m_xDialog.get(), aSet)); + pDlg->SetText( aTxt ); + + if ( executeSubDialog(pDlg.get()) == RET_OK ) + { + 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 AttributText 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 ) + return; + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr pDlg(pFact->CreateSvxSearchAttributeDialog(m_xDialog.get(), *pSearchList, pImpl->pRanges.get())); + 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); + 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(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(_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* pViewFrame = SfxViewFrame::Current(); + if (!pViewFrame) + return; + + bool bNotFound = rStr == SvxResId(RID_SVXSTR_SEARCH_NOT_FOUND); + + 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; + 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( VCLUnoHelper::GetWindow(xWindow).get() ); + for (ToolBox::ImplToolItems::size_type i = 0; pToolBox && i < pToolBox->GetItemCount(); ++i) + { + sal_uInt16 id = pToolBox->GetItemId(i); + if (pToolBox->GetItemCommand(id) == ".uno:SearchLabel") + { + LabelItemWindow* pSearchLabel = dynamic_cast(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(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( VCLUnoHelper::GetWindow(xWindow).get() ); + for (ToolBox::ImplToolItems::size_type i = 0; pToolBox && i < pToolBox->GetItemCount(); ++i) + { + sal_uInt16 id = pToolBox->GetItemId(i); + if (pToolBox->GetItemCommand(id) == ".uno:SearchLabel") + { + LabelItemWindow* pSearchLabel = dynamic_cast(pToolBox->GetItemWindow(id)); + return pSearchLabel ? pSearchLabel->get_label() : OUString(); + } + } + return OUString(); +} + +void SvxSearchDialogWrapper::SetSearchLabel(const SearchLabel& rSL) +{ + 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); + if (SvxSearchDialogWrapper *pWrp = static_cast( SfxViewFrame::Current()-> + GetChildWindow( SvxSearchDialogWrapper::GetChildWindowId() ))) + pWrp->getDialog()->SetSearchLabel(sStr); +} + +void SvxSearchDialogWrapper::SetSearchLabel(const OUString& sStr) +{ + + lcl_SetSearchLabelWindow(sStr); + if (SvxSearchDialogWrapper *pWrp = static_cast( SfxViewFrame::Current()-> + 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..2742c3f95 --- /dev/null +++ b/svx/source/dialog/strarray.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 +#include +#include +#include +#include +#include + +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..e04ae513d --- /dev/null +++ b/svx/source/dialog/svxbmpnumvalueset.cxx @@ -0,0 +1,524 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 +static 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) ); + } +} + +static const char* 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 +}; + +static const char* 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 +}; + +static const char* 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(); + + long nRectWidth = aRect.GetWidth(); + 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::getSystemLanguage(), 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::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 + const OUString sValue("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 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(i + 1); + sText = xFormatter->makeNumberingString( aLevel, aLocale ); + } + catch(Exception&) + { + OSL_FAIL("Exception in DefaultNumberingProvider::makeNumberingString"); + } + } + // 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); + long nStartX = aOrgRect.TopLeft().X(); + long nStartY = aOrgRect.TopLeft().Y(); + + if(xFormatter.is() && aOutlineSettings.getLength() > nItemId - 1) + { + Reference 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++) + { + 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 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&) + { + OSL_FAIL("Exception in DefaultNumberingProvider::makeNumberingString"); + } + + 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(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]) ); + } + + 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) + { + OSL_FAIL("exception in ::UserDraw"); + 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 pScrolledWindow) + : ValueSet(std::move(pScrolledWindow)) + , ePageType(NumberingPageType::BULLET) + , pVDev(nullptr) +{ +} + +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 >& aNum, + Reference 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 > const & rOutline, + Reference 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 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(); + + 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..152811ed8 --- /dev/null +++ b/svx/source/dialog/svxdlg.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 + +SvxAbstractDialogFactory* SvxAbstractDialogFactory::Create() +{ + return dynamic_cast< SvxAbstractDialogFactory* >( VclAbstractDialogFactory::Create() ); +} + +SvxAbstractDialogFactory::~SvxAbstractDialogFactory() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/dialog/svxgrahicitem.cxx b/svx/source/dialog/svxgrahicitem.cxx new file mode 100644 index 000000000..6a64afba8 --- /dev/null +++ b/svx/source/dialog/svxgrahicitem.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 +#include + +SvxGraphicItem::SvxGraphicItem( const Graphic& rGraphic ) + : SfxPoolItem( SID_GRAPHIC ), aGraphic( rGraphic ) +{ + +} + +bool SvxGraphicItem::operator==( const SfxPoolItem& rItem) const +{ + return SfxPoolItem::operator==(rItem) && static_cast(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..1e53d7a3a --- /dev/null +++ b/svx/source/dialog/svxruler.cxx @@ -0,0 +1,3559 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rlrcitem.hxx" +#include + +#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 pPercBuf; + std::unique_ptr pBlockBuf; + sal_uInt16 nPercSize; + long nTotalDist; + long lOldWinPos; + long lMaxLeftLogic; + long lMaxRightLogic; + long lLastLMargin; + long lLastRMargin; + std::unique_ptr aProtectItem; + std::unique_ptr pTextRTLItem; + sal_uInt16 nControlerItems; + 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(SID_RULER_PROTECT)), + nControlerItems(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 + +static constexpr 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->nControlerItems=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(); +} + +long SvxRuler::MakePositionSticky(long aPosition, long aPointOfReference, bool aSnapToFrameMargin) const +{ + long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference); + long aLeftFramePosition = ConvertHPosPixel(GetLeftFrameMargin()); + long aRightFramePosition = ConvertHPosPixel(GetRightFrameMargin()); + + double aTick = GetCurrentRulerUnit().nTick1; + + if (mbCoarseSnapping) + aTick = GetCurrentRulerUnit().nTick2; + + 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 + long aTranslatedPosition = aPosition - aPointOfReferencePixel; + // Convert position to current selected map mode + 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; +} + +long SvxRuler::ConvertHPosPixel(long nVal) const +{ + return pEditWin->LogicToPixel(Size(nVal, 0)).Width(); +} + +long SvxRuler::ConvertVPosPixel(long nVal) const +{ + return pEditWin->LogicToPixel(Size(0, nVal)).Height(); +} + +long SvxRuler::ConvertHSizePixel(long nVal) const +{ + return pEditWin->LogicToPixel(Size(nVal, 0)).Width(); +} + +long SvxRuler::ConvertVSizePixel(long nVal) const +{ + return pEditWin->LogicToPixel(Size(0, nVal)).Height(); +} + +long SvxRuler::ConvertPosPixel(long nVal) const +{ + return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal); +} + +long SvxRuler::ConvertSizePixel(long nVal) const +{ + return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal); +} + +inline long SvxRuler::ConvertHPosLogic(long nVal) const +{ + return pEditWin->PixelToLogic(Size(nVal, 0)).Width(); +} + +inline long SvxRuler::ConvertVPosLogic(long nVal) const +{ + return pEditWin->PixelToLogic(Size(0, nVal)).Height(); +} + +inline long SvxRuler::ConvertHSizeLogic(long nVal) const +{ + return pEditWin->PixelToLogic(Size(nVal, 0)).Width(); +} + +inline long SvxRuler::ConvertVSizeLogic(long nVal) const +{ + return pEditWin->PixelToLogic(Size(0, nVal)).Height(); +} + +inline long SvxRuler::ConvertPosLogic(long nVal) const +{ + return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal); +} + +inline long SvxRuler::ConvertSizeLogic(long nVal) const +{ + return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal); +} + +long SvxRuler::PixelHAdjust(long nVal, long nValOld) const +{ + if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld)) + return nVal; + else + return nValOld; +} + +long SvxRuler::PixelVAdjust(long nVal, long nValOld) const +{ + if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld)) + return nVal; + else + return nValOld; +} + +long SvxRuler::PixelAdjust(long nVal, 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 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); + } + + long lRight = 0; + + // evaluate the table right edge of the table + if(mxColumnItem && mxColumnItem->IsTable()) + lRight = mxColumnItem->GetRight(); + else + lRight = mxLRSpaceItem->GetRight(); + + long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset; + long aWidthPixel = ConvertHPosPixel(aWidth); + + SetMargin2(aWidthPixel, nMarginStyle); + } + else if(mxULSpaceItem && mxPagePosItem) + { + // relative the upper edge of the surrounding frame + const 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); + } + + long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower(); + long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset; + long nMargin2Pixel = ConvertVPosPixel(nMargin2); + + SetMargin2(nMargin2Pixel, nMarginStyle); + } + else + { + // turns off the view + SetMargin1(); + SetMargin2(); + } + + if (mxColumnItem) + { + mxRulerImpl->nColLeftPix = static_cast(ConvertSizePixel(mxColumnItem->GetLeft())); + mxRulerImpl->nColRightPix = static_cast(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; + + long nIndex = aSelection.nAryPos + INDENT_GAP; + + 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: + { + 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: + { + 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) + { + 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 + 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 + long nLeftFrameMargin = GetLeftFrameMargin(); + long nRightFrameMargin = GetRightFrameMargin(); + SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin)); + SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin)); + + long leftMargin; + long leftFirstLine; + 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::UpdateParaBorder() +{ + /* Border distance */ + if(bActive) + { + 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(); + } + + 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(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; + 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 long nLeftFrameMargin = GetLeftFrameMargin(); + const long nRightFrameMargin = GetRightFrameMargin(); + + //#i24363# tab stops relative to indent + const long nParaItemTxtLeft = mxParaItem->GetTextLeft(); + + const long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft; + const long lRightMargin = nRightFrameMargin - nParaItemTxtLeft; + + const long lLastTab = mxTabStopItem->Count() + ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos()) + : 0; + const long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab; + const long lRightIndent = ConvertHPosPixel(nRightFrameMargin - mxParaItem->GetRight()); + + long nDefTabDist = ConvertHPosPixel(lDefTabDist); + + if( !nDefTabDist ) + nDefTabDist = 1; + + const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent + ? 0 + : static_cast( (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 long lParaIndentPix = ConvertSizePixel(lParaIndent); + + long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin) + + lAppNullOffset; + if (bRTL) + { + lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic; + } + long lLastTabOffsetLogic = 0; + for(j = 0; j < mxTabStopItem->Count(); ++j) + { + const SvxTabStop* pTab = &mxTabStopItem->At(j); + lLastTabOffsetLogic = pTab->GetTabPos(); + 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) + { + 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(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(); +} + +long SvxRuler::GetPageWidth() const +{ + if (!mxPagePosItem) + return 0; + return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight(); +} + +inline long SvxRuler::GetFrameLeft() const +{ + /* Get Left margin in Pixels */ + return bAppSetNullOffset ? + GetMargin1() + ConvertSizePixel(lLogicNullOffset) : + Ruler::GetNullOffset(); +} + +long SvxRuler::GetFirstLineIndent() const +{ + /* Get First-line indent in pixels */ + return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1(); +} + +long SvxRuler::GetLeftIndent() const +{ + /* Get Left paragraph margin in Pixels */ + return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1(); +} + +long SvxRuler::GetRightIndent() const +{ + /* Get Right paragraph margin in Pixels */ + return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2(); +} + +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. +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!"); + long nLeft = 0; + if (mxColumnItem && + mxColumnItem->Count() && + mxColumnItem->IsConsistent()) + { + nLeft = mxColumnItem->GetActiveColumnDescription().nStart; + } + + return nLeft; +} + +inline 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 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; +} + + +long SvxRuler::GetRightFrameMargin() const +{ + /* Get right frame margin (in logical units) */ + if (mxColumnItem) + { + if (!IsActLastColumn(true)) + { + return mxColumnItem->At(GetActRightColumn(true)).nEnd; + } + } + + 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) + 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() ) + +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 long lNullPix = Ruler::GetNullOffset(); + 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 + 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 */ + 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(long lInputDiff) +{ + const long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset(); + const long lDragPos = lInputDiff; + + bool bProtectColumns = + mxRulerImpl->aProtectItem->IsSizeProtected() || + mxRulerImpl->aProtectItem->IsPosProtected(); + + const RulerMarginStyle nMarginStyle = + bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable; + + if(!bAppSetNullOffset) + { + 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 + { + 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 */ + long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG); + aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false); + 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 */ + 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 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(long& lTabPosition, int nNew, bool bHorizontal) +{ + /* + Output routine for the ledger line when moving tabs, tables and other + columns + */ + if(bHorizontal) + { + const long nHeight = pEditWin->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 ) + { + 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 long nWidth = pEditWin->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) + { + 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 */ + long aDragPosition = GetCorrectedDragPos(true, false); + aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin()); + + sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP; + 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; + 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;inControlerItems;i++) + pCtrlItems[i]->ReBind(); + else + for(sal_uInt16 j=0;jnControlerItems;j++) + pCtrlItems[j]->UnBind(); + pBindings->LeaveRegistrations(); + } + bActive = bOn; +} + +void SvxRuler::UpdateParaContents_Impl( + 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(); + long lDiff = 0; + + // the drag position has to be corrected to be able to prevent borders from passing each other + 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) + { + long nRight = GetMargin2() - glMinFrame; // Right limiters + for(int i = mpBorders.size() - 2; i >= nIndex; --i) + { + 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; + 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) + { + + 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 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 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 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; + } + + long nRight; + if(mxRulerImpl->lMaxRightLogic != -1 + && nMaxRight == GetMargin2() + Ruler::GetNullOffset()) + { + nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic; + } + else + { + nRight = std::max(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 long lOldNull = lLogicNullOffset; + lLogicNullOffset = + ConvertVPosLogic(GetFrameLeft()) - + lAppNullOffset; + mxULSpaceItem->SetUpper( + PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper())); + if(bAppSetNullOffset) + { + lAppNullOffset += lLogicNullOffset - lOldNull; + } + mxULSpaceItem->SetLower( + PixelVAdjust( + std::max(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(); +} + +long SvxRuler::RoundToCurrentMapMode(long lValue) const +{ + RulerUnitData aUnitData = GetCurrentRulerUnit(); + double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1; + + long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width(); + lNewValue = (rtl::math::round(lNewValue / static_cast(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. */ + + long nLeftFrameMargin = GetLeftFrameMargin(); + + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + + long nNewTxtLeft; + long nNewFirstLineOffset; + long nNewRight; + + long nFirstLine = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos); + long nLeftMargin = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos); + long nRightMargin = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos); + + if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true)))) + { + if(bRTL) + { + long nRightColumn = GetActRightColumn(true); + long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos); + nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset; + } + else + { + long nLeftColumn = GetActLeftColumn(true); + long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth); + nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset; + } + } + else + { + if(bRTL) + { + long nRightBorder = ConvertPosLogic(GetMargin2()); + nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset; + } + else + { + 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) + { + long nLeftColumn = GetActLeftColumn(true); + long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth); + nNewRight = nRightMargin - nLeftBorder - lAppNullOffset; + } + else + { + long nRightColumn = GetActRightColumn(true); + long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos); + nNewRight = nRightBorder - nRightMargin - lAppNullOffset; + } + } + else + { + if(bRTL) + { + long nLeftBorder = ConvertPosLogic(GetMargin1()); + nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset; + } + else + { + 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(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 + 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 long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ? + GetLeftIndent() : + ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ); + + long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos); + aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos()); + } + else + { + //#i24363# tab stops relative to indent + const long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ? + GetLeftIndent() : + ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ); + + 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()) + { + long lValue = GetFrameLeft(); + if(lValue != mxRulerImpl->nColLeftPix) + { + long nLeft = PixelHAdjust( + ConvertHPosLogic(lValue) - + lAppNullOffset, + mxColumnItem->GetLeft()); + mxColumnItem->SetLeft(nLeft); + } + + lValue = GetMargin2(); + + if(lValue != mxRulerImpl->nColRightPix) + { + long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight(); + long nRight = PixelHAdjust( + nWidthOrHeight - + mxColumnItem->GetLeft() - + ConvertHPosLogic(lValue) - + lAppNullOffset, + mxColumnItem->GetRight() ); + mxColumnItem->SetRight(nRight); + } + } + + for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i) + { + long& nEnd = mxColumnItem->At(i).nEnd; + nEnd = PixelHAdjust( + ConvertPosLogic(mpBorders[i].nPos), + mxColumnItem->At(i).nEnd); + 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 + long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0; + long nStartX = PixelAdjust( + ConvertPosLogic(mpObjectBorders[0].nPos) + + nMargin - + lAppNullOffset, + mxObjectItem->GetStartX()); + mxObjectItem->SetStartX(nStartX); + + long nEndX = PixelAdjust( + ConvertPosLogic(mpObjectBorders[1].nPos) + + nMargin - + lAppNullOffset, + mxObjectItem->GetEndX()); + mxObjectItem->SetEndX(nEndX); + + nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0; + long nStartY = PixelAdjust( + ConvertPosLogic(mpObjectBorders[2].nPos) + + nMargin - + lAppNullOffset, + mxObjectItem->GetStartY()); + mxObjectItem->SetStartY(nStartY); + + 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()); + + long lPos; + long lWidth=0; + sal_uInt16 nStart; + sal_uInt16 nIdx=GetDragAryPos(); + long lActWidth=0; + long lActBorderSum; + 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((lActWidth * 1000) + / mxRulerImpl->nTotalDist); + mxRulerImpl->pBlockBuf[i] = static_cast(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((lActWidth * 1000) + / mxRulerImpl->nTotalDist); + mxRulerImpl->pBlockBuf[i] = static_cast(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 long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos; + mxRulerImpl->pPercBuf[i] = static_cast((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) + { + bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected(); + if( bContentProtected ) return; + const long lPos = GetClickPos(); + if((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) || + (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent())) + { + //convert position in left-to-right text + 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 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()) + { + 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 ) + { + 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 ) + { + 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] + + + + + */ + 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 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->nControlerItems; 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; + } +} + +IMPL_LINK( SvxRuler, MenuSelect, Menu *, pMenu, bool ) +{ + /* Handler of the context menus for switching the unit of measurement */ + SetUnit(vcl::StringToMetric(OUString::fromUtf8(pMenu->GetCurItemIdent()))); + return false; +} + +IMPL_LINK( SvxRuler, TabMenuSelect, Menu *, pMenu, bool ) +{ + /* 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(pMenu->GetCurItemId() - 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; + } + return false; +} + +static const char* 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(); + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + if ( !mpTabs.empty() && + RulerType::Tab == + GetType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) && + mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT ) + { + ScopedVclPtrInstance aMenu; + aMenu->SetSelectHdl(LINK(this, SvxRuler, TabMenuSelect)); + ScopedVclPtrInstance< VirtualDevice > pDev; + const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2); + pDev->SetOutputSize(aSz); + pDev->SetBackground(Wallpaper(COL_WHITE)); + Color aFillColor(pDev->GetSettings().GetStyleSettings().GetShadowColor()); + const Point aPt(aSz.Width() / 2, aSz.Height() / 2); + + for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i ) + { + sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i; + nStyle |= static_cast(bHorz ? WB_HORZ : WB_VERT); + DrawTab(*pDev, aFillColor, aPt, nStyle); + BitmapEx aItemBitmapEx(pDev->GetBitmapEx(Point(), aSz)); + aItemBitmapEx.Replace(COL_WHITE, COL_TRANSPARENT); + aMenu->InsertItem(i + 1, + SvxResId(RID_SVXSTR_RULER_TAB[i]), + Image(aItemBitmapEx)); + aMenu->CheckItem(i + 1, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle); + pDev->SetOutputSize(aSz); // delete device + } + aMenu->Execute( this, rCommandEvent.GetMousePosPixel() ); + } + else + { + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/rulermenu.ui", ""); + VclPtr aMenu(aBuilder.get_menu("menu")); + aMenu->SetSelectHdl(LINK(this, SvxRuler, MenuSelect)); + FieldUnit eUnit = GetUnit(); + const sal_uInt16 nCount = aMenu->GetItemCount(); + + bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC); + for ( sal_uInt16 i = nCount; i; --i ) + { + sal_uInt16 nId = aMenu->GetItemId(i - 1); + OString sIdent = aMenu->GetItemIdent(nId); + FieldUnit eMenuUnit = vcl::StringToMetric(OUString::fromUtf8(sIdent)); + aMenu->CheckItem(nId, eMenuUnit == eUnit); + if( bReduceMetric ) + { + if (eMenuUnit == FieldUnit::M || + eMenuUnit == FieldUnit::KM || + eMenuUnit == FieldUnit::FOOT || + eMenuUnit == FieldUnit::MILE) + { + aMenu->RemoveItem(i - 1); + } + else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz ) + { + aMenu->RemoveItem(i - 1); + } + else if (( eMenuUnit == FieldUnit::LINE ) && bHorz ) + { + aMenu->RemoveItem(i - 1); + } + } + } + aMenu->Execute( this, rCommandEvent.GetMousePosPixel() ); + } + } + 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; +} + +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 + long _nMaxRight = GetMargin2() - GetMargin1(); + + long lFences = 0; + long lMinSpace = USHRT_MAX; + long lOldPos; + 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) + { + long lWidth = mpBorders[i].nPos - lOldPos; + lColumns += lWidth; + if(lWidth < lMinSpace) + lMinSpace = lWidth; + lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth; + lFences += mpBorders[i].nWidth; + } + 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); + } + + 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(lFences + glMinFrame / static_cast(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 + { + 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, long diffValue) +{ + if (diffValue == 0) + return; + + if (type == RulerChangeType::MARGIN1) + AdjustMargin1(diffValue); + else if (type == RulerChangeType::MARGIN2) + SetMargin2( GetMargin2() - diffValue); + ApplyMargins(); +} diff --git a/svx/source/dialog/swframeexample.cxx b/svx/source/dialog/swframeexample.cxx new file mode 100644 index 000000000..ab866786b --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::text; + +#define FLYINFLY_BORDER 3 +#define DEMOTEXT "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((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(5L, aFrmSize.Width()) ); + aFrmSize.setHeight( std::max(5L, aFrmSize.Height()) ); + } + else + { + sal_uInt32 nFreeWidth = aPagePrtArea.GetWidth() - rRenderContext.GetTextWidth(DEMOTEXT); + + aFrmSize = Size(nFreeWidth / 2, (aTextLine.GetHeight() + 2) * 3); + aDrawObj.SetSize(Size(std::max(5L, static_cast(nFreeWidth) / 3L), std::max(5L, aFrmSize.Height() * 3L))); + 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_RIGHT: + rRect.SetLeft( aFrameAtFrame.Left() ); + rRect.SetRight( aFrameAtFrame.Left() + FLYINFLY_BORDER ); + break; + + case RelOrientation::PAGE_LEFT: + 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(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); + + long lXPos = 0; + 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 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(((aFrameAtFrame.GetHeight() - 2 * FLYINFLY_BORDER) * 2 / 3) + / (aTxt.GetHeight() + 2)); + } + else + { + nStep = aTxt.GetHeight() + 2; + nLines = static_cast(aParaPrtArea.GetHeight() / (aTextLine.GetHeight() + 2)); + } + + if (nAnchor != RndStdIds::FLY_AS_CHAR) + { + // Simulate text + const long nOldR = aTxt.Right(); + const 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.IsOver(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->IsInside(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.IsOver(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 + +#include + +#include +#include +#include + +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..4229ea109 --- /dev/null +++ b/svx/source/dialog/txencbox.cxx @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#if HAVE_FEATURE_DBCONNECTIVITY +#include +#endif +#include +#include +#include +#include + +namespace +{ + std::vector FillFromDbTextEncodingMap(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags) + { + std::vector 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; jfreeze(); + 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 pControl) + : m_xControl(std::move(pControl)) +{ + m_xControl->make_sorted(); +} + +SvxTextEncodingTreeView::SvxTextEncodingTreeView(std::unique_ptr pControl) + : m_xControl(std::move(pControl)) +{ + m_xControl->make_sorted(); +} + +SvxTextEncodingBox::~SvxTextEncodingBox() +{ +} + +SvxTextEncodingTreeView::~SvxTextEncodingTreeView() +{ +} + +namespace +{ + std::vector FillFromTextEncodingTable(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags, sal_uInt32 nButIncludeInfoFlags) + { + std::vector 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 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 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::FillWithMimeAndSelectBest() +{ + FillFromTextEncodingTable( false, 0xffffffff, RTL_TEXTENCODING_INFO_MIME ); + rtl_TextEncoding nEnc = SvtSysLocale::GetBestMimeEncoding(); + SelectTextEncoding( nEnc ); +} + +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( 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( 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 +#include +#include + +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..12c6a94cd --- /dev/null +++ b/svx/source/dialog/weldeditview.cxx @@ -0,0 +1,1482 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +WeldEditView::WeldEditView() {} + +// tdf#127033 want to use UI font so override makeEditEngine to enable that +void WeldEditView::makeEditEngine() +{ + 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)); +} + +void WeldEditView::Resize() +{ + OutputDevice& rDevice = GetDrawingArea()->get_ref_device(); + Size aOutputSize(rDevice.PixelToLogic(GetOutputSizePixel())); + Size aSize(aOutputSize); + m_xEditEngine->SetPaperSize(aSize); + m_xEditView->SetOutputArea(tools::Rectangle(Point(0, 0), aOutputSize)); + weld::CustomWidgetController::Resize(); +} + +void WeldEditView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + //note: ScEditWindow::Paint is similar + + rRenderContext.Push(PushFlags::ALL); + rRenderContext.SetClipRegion(); + + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + Color aBgColor = rStyleSettings.GetWindowColor(); + + m_xEditView->SetBackgroundColor(aBgColor); + + rRenderContext.SetBackground(aBgColor); + + tools::Rectangle aLogicRect(rRenderContext.PixelToLogic(rRect)); + m_xEditView->Paint(aLogicRect, &rRenderContext); + + if (HasFocus()) + { + m_xEditView->ShowCursor(); + vcl::Cursor* pCursor = m_xEditView->GetCursor(); + pCursor->DrawToDevice(rRenderContext); + } + + std::vector aLogicRects; + + // get logic selection + m_xEditView->GetSelectionRectangles(aLogicRects); + + rRenderContext.SetLineColor(); + rRenderContext.SetFillColor(COL_BLACK); + rRenderContext.SetRasterOp(RasterOp::Invert); + + for (const auto& rSelectionRect : aLogicRects) + rRenderContext.DrawRect(rSelectionRect); + + rRenderContext.Pop(); +} + +bool WeldEditView::MouseMove(const MouseEvent& rMEvt) { return m_xEditView->MouseMove(rMEvt); } + +bool WeldEditView::MouseButtonDown(const MouseEvent& rMEvt) +{ + if (!HasFocus()) + { + GrabFocus(); + GetFocus(); + } + + return m_xEditView->MouseButtonDown(rMEvt); +} + +bool WeldEditView::MouseButtonUp(const MouseEvent& rMEvt) +{ + return m_xEditView->MouseButtonUp(rMEvt); +} + +bool WeldEditView::KeyInput(const KeyEvent& rKEvt) +{ + sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode(); + + if (nKey == KEY_TAB) + { + return false; + } + else if (!m_xEditView->PostKeyEvent(rKEvt)) + { + if (rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2()) + { + if (nKey == KEY_A) + { + sal_Int32 nPar = m_xEditEngine->GetParagraphCount(); + if (nPar) + { + sal_Int32 nLen = m_xEditEngine->GetTextLen(nPar - 1); + m_xEditView->SetSelection(ESelection(0, 0, nPar - 1, nLen)); + } + return true; + } + } + + return false; + } + + return true; +} + +bool WeldEditView::Command(const CommandEvent& rCEvt) +{ + m_xEditView->Command(rCEvt); + return true; +} + +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& 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& rpTxtColor, + std::optional& 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 Clone() const override + { + return std::unique_ptr(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(this)->m_aBroadCaster; + } +}; +} + +typedef cppu::WeakImplHelper< + 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(*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()); + + 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()); + + //! make TextHelper release references + //! (e.g. the one set by the 'SetEventSource' call) + m_xTextHelper->Dispose(); + m_xTextHelper.reset(); + } + + // XAccessible + virtual css::uno::Reference + 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 + 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); + + css::uno::Reference xParent(getAccessibleParent()); + if (xParent) + { + css::uno::Reference xParentContext( + xParent->getAccessibleContext()); + css::uno::Reference xParentComponent( + xParentContext, css::uno::UNO_QUERY); + OSL_ENSURE(xParentComponent.is(), + "WeldEditAccessible::getLocationOnScreen: no parent component!"); + if (xParentComponent.is()) + { + css::awt::Point aParentScreenLoc(xParentComponent->getLocationOnScreen()); + css::awt::Point aOwnRelativeLoc(getLocation()); + aScreenLoc.X = aParentScreenLoc.X + aOwnRelativeLoc.X; + aScreenLoc.Y = aParentScreenLoc.Y + aOwnRelativeLoc.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(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(nCol); + } + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount() override + { + if (m_xTextHelper) + return m_xTextHelper->GetChildCount(); + return 0; + } + + virtual css::uno::Reference + 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 + 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 xParent(getAccessibleParent()); + if (!xParent) + return nRet; + + try + { + css::uno::Reference 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 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 + 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 + SAL_CALL getAccessibleStateSet() override + { + SolarMutexGuard aGuard; + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper; + + css::uno::Reference xStateSet(pStateSet); + + 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 xStateSet; + } + + 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& 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& rListener) override + { + if (!m_xTextHelper) // not disposing (about to destroy view shell) + return; + m_xTextHelper->RemoveEventListener(rListener); + } +}; + +css::uno::Reference WeldEditView::CreateAccessible() +{ + if (!m_xAccessible.is()) + m_xAccessible.set(new WeldEditAccessible(this)); + return css::uno::Reference(m_xAccessible.get()); +} + +WeldEditView::~WeldEditView() +{ + if (m_xAccessible.is()) + { + m_xAccessible->ClearWin(); // make Accessible nonfunctional + m_xAccessible.clear(); + } +} + +bool WeldViewForwarder::IsValid() const { return m_rEditAcc.GetEditView() != nullptr; } + +Point WeldViewForwarder::LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const +{ + EditView* pEditView = m_rEditAcc.GetEditView(); + OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr; + + if (pOutDev) + { + MapMode aMapMode(pOutDev->GetMapMode()); + Point aPoint(OutputDevice::LogicToLogic(rPoint, rMapMode, MapMode(aMapMode.GetMapUnit()))); + aMapMode.SetOrigin(Point()); + return pOutDev->LogicToPixel(aPoint, aMapMode); + } + + return Point(); +} + +Point WeldViewForwarder::PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const +{ + EditView* pEditView = m_rEditAcc.GetEditView(); + OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr; + + if (pOutDev) + { + MapMode aMapMode(pOutDev->GetMapMode()); + aMapMode.SetOrigin(Point()); + Point aPoint(pOutDev->PixelToLogic(rPoint, aMapMode)); + return OutputDevice::LogicToLogic(aPoint, MapMode(aMapMode.GetMapUnit()), rMapMode); + } + + return Point(); +} + +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()); +} + +IMPL_LINK(WeldTextForwarder, NotifyHdl, EENotify&, rNotify, void) +{ + ::std::unique_ptr 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& 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->GetUpdateMode(); +} + +OUString WeldTextForwarder::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, + sal_Int32 nPos, std::optional& rpTxtColor, + std::optional& 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 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) : 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(&rSource); + if (!pSourceForwarder) + return; + EditEngine* pSourceEditEngine = pSourceForwarder->m_rEditAcc.GetEditEngine(); + EditEngine* pEditEngine = m_rEditAcc.GetEditEngine(); + if (pEditEngine && pSourceEditEngine) + { + std::unique_ptr 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(); + OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr; + + if (pOutDev) + { + MapMode aMapMode(pOutDev->GetMapMode()); + Point aPoint(OutputDevice::LogicToLogic(rPoint, rMapMode, MapMode(aMapMode.GetMapUnit()))); + aMapMode.SetOrigin(Point()); + return pOutDev->LogicToPixel(aPoint, aMapMode); + } + + return Point(); +} + +Point WeldEditViewForwarder::PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const +{ + EditView* pEditView = m_rEditAcc.GetEditView(); + OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr; + + if (pOutDev) + { + MapMode aMapMode(pOutDev->GetMapMode()); + aMapMode.SetOrigin(Point()); + Point aPoint(pOutDev->PixelToLogic(rPoint, aMapMode)); + return OutputDevice::LogicToLogic(aPoint, MapMode(aMapMode.GetMapUnit()), rMapMode); + } + + return Point(); +} + +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)); + aSize = aOutputSize; + aSize.setHeight(aSize.Height()); + + makeEditEngine(); + m_xEditEngine->SetPaperSize(aSize); + 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->InsertView(m_xEditView.get()); + + pDrawingArea->set_cursor(PointerStyle::Text); + + if (m_xAccessible.is()) + m_xAccessible->Init(m_xEditEngine.get(), m_xEditView.get()); +} + +int WeldEditView::GetSurroundingText(OUString& rSurrounding) +{ + rSurrounding = m_xEditView->GetSurroundingText(); + return m_xEditView->GetSurroundingTextSelection().Min(); +} + +bool WeldEditView::DeleteSurroundingText(const Selection& rRange) +{ + bool bRes(false); + EditEngine* pEditEngine = m_xEditView->GetEditEngine(); + if (pEditEngine) + { + ESelection aSel(m_xEditView->GetSelection()); + aSel.nEndPara = aSel.nStartPara; + aSel.nStartPos = rRange.Min(); + aSel.nEndPos = rRange.Max(); + pEditEngine->QuickDelete(aSel); + pEditEngine->QuickFormatDoc(); + bRes = true; + } + return bRes; +} + +void WeldEditView::GetFocus() +{ + m_xEditView->ShowCursor(); + + weld::CustomWidgetController::GetFocus(); + + if (m_xAccessible.is()) + { + // Note: will implicitly send the AccessibleStateType::FOCUSED event + ::accessibility::AccessibleTextHelper* pHelper = m_xAccessible->GetTextHelper(); + if (pHelper) + pHelper->SetFocus(); + } +} + +void WeldEditView::LoseFocus() +{ + weld::CustomWidgetController::LoseFocus(); + Invalidate(); // redraw without cursor + + if (m_xAccessible.is()) + { + // Note: will implicitly send the AccessibleStateType::FOCUSED event + ::accessibility::AccessibleTextHelper* pHelper = m_xAccessible->GetTextHelper(); + if (pHelper) + pHelper->SetFocus(false); + } +} + +/* 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..abb7b3991 --- /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 + +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..401e1b085 --- /dev/null +++ b/svx/source/engine3d/cube3d.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 +#include +#include +#include +#include +#include +#include +#include + + +// DrawContact section + +std::unique_ptr E3dCubeObj::CreateObjectSpecificViewContact() +{ + return std::make_unique(*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() +{ +} + +void E3dCubeObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault) +{ + aCubePos = rDefault.GetDefaultCubePos(); + aCubeSize = rDefault.GetDefaultCubeSize(); + bPosIsCenter = rDefault.GetDefaultCubePosIsCenter(); +} + +sal_uInt16 E3dCubeObj::GetObjIdentifier() const +{ + return E3D_CUBEOBJ_ID; +} + +// 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 CloneHelper< E3dCubeObj >(rTargetModel); +} + +E3dCubeObj& E3dCubeObj::operator=(const E3dCubeObj& rObj) +{ + if( this == &rObj ) + return *this; + E3dCompoundObject::operator=(rObj); + + aCubePos = rObj.aCubePos; + aCubeSize = rObj.aCubeSize; + bPosIsCenter = rObj.bPosIsCenter; + + return *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 +{ + OUStringBuffer sName(SvxResId(STR_ObjNameSingulCube3d)); + + OUString aName(GetName()); + if (!aName.isEmpty()) + { + sName.append(' '); + sName.append('\''); + sName.append(aName); + sName.append('\''); + } + return sName.makeStringAndClear(); +} + +// 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..76589032b --- /dev/null +++ b/svx/source/engine3d/deflt3d.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 + +// 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..231305eea --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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; + } + } + 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( + 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 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) + { + const E3dScene* pScene(maGrp[0].mr3DObj.getRootE3dSceneFromE3dObject()); + + if(nullptr != pScene) + { + 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(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)) + { + // Get modifier + sal_uInt16 nModifier = 0; + if(dynamic_cast(&getSdrDragView())) + { + const MouseEvent& rLastMouse = static_cast(getSdrDragView()).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) + { + fWAngle = NormAngle36000(GetAngle(rPnt - DragStat().GetRef1()) - + rCandidate.mnStartAngle) - rCandidate.mnLastAngle; + rCandidate.mnLastAngle = static_cast(fWAngle) + rCandidate.mnLastAngle; + fWAngle /= 100.0; + fHAngle = 0.0; + } + else + { + if ((maFullBound.GetWidth() == 0) || (maFullBound.GetHeight() == 0)) + throw o3tl::divide_by_zero(); + fWAngle = 90.0 * static_cast(rPnt.X() - maLastPos.X()) + / static_cast(maFullBound.GetWidth()); + fHAngle = 90.0 * static_cast(rPnt.Y() - maLastPos.Y()) + / static_cast(maFullBound.GetHeight()); + } + long nSnap = 0; + + if(!getSdrDragView().IsRotateAllowed()) + nSnap = 90; + + if(nSnap != 0) + { + fWAngle = static_cast((static_cast(fWAngle) + nSnap/2) / nSnap * nSnap); + fHAngle = static_cast((static_cast(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)) + { + if(SdrHdlKind::Move == meWhatDragHdl) + { + // Translation + // Determine the motion vector + const sal_uInt32 nCnt(maGrp.size()); + + // Get modifier + sal_uInt16 nModifier(0); + + if(dynamic_cast(&getSdrDragView())) + { + const MouseEvent& rLastMouse = static_cast(getSdrDragView()).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(rPnt.X() - maLastPos.X()), static_cast(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(aStartPos.X()), static_cast(aStartPos.Y())); + basegfx::B2DPoint aGlobalScaleNext2D(static_cast(rPnt.X()), static_cast(rPnt.Y())); + basegfx::B2DPoint aGlobalScaleFixPos2D(static_cast(maScaleFixPos.X()), static_cast(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..07df1af05 --- /dev/null +++ b/svx/source/engine3d/e3dsceneupdater.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 +#include +#include +#include +#include + + +E3DModifySceneSnapRectUpdater::E3DModifySceneSnapRectUpdater(const SdrObject* pObject) +: mpScene(nullptr) +{ + // Secure old 3D transformation stack before modification + if(const E3dObject* pE3dObject = dynamic_cast< const E3dObject* >(pObject)) + { + mpScene = pE3dObject->getRootE3dSceneFromE3dObject(); + + if(nullptr != mpScene && mpScene->getRootE3dSceneFromE3dObject() == mpScene) + { + // 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.reset( + new drawinglayer::geometry::ViewInformation3D( + rVCScene.getViewInformation3D(aAllContentRange))); + } + } + } +} + +E3DModifySceneSnapRectUpdater::~E3DModifySceneSnapRectUpdater() +{ + if(mpScene && mpViewInformation3D) + { + // 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()) + { + // 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 + drawinglayer::geometry::ViewInformation3D* pNew = new drawinglayer::geometry::ViewInformation3D( + mpScene->GetTransform(), // replace object transformation with new local transform + mpViewInformation3D->getOrientation(), + mpViewInformation3D->getProjection(), + mpViewInformation3D->getDeviceToView(), + mpViewInformation3D->getViewTime(), + mpViewInformation3D->getExtendedInformationSequence()); + mpViewInformation3D.reset(pNew); + } + + // 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 +#include + + +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..d4aa1f024 --- /dev/null +++ b/svx/source/engine3d/extrud3d.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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// DrawContact section +std::unique_ptr E3dExtrudeObj::CreateObjectSpecificViewContact() +{ + return std::make_unique(*this); +} + +std::unique_ptr E3dExtrudeObj::CreateObjectSpecificProperties() +{ + return std::make_unique(*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(fDepth + 0.5))); +} + +E3dExtrudeObj::E3dExtrudeObj(SdrModel& rSdrModel) +: E3dCompoundObject(rSdrModel) +{ + // Set Defaults + const E3dDefaultAttributes aDefault; + + SetDefaultAttributes(aDefault); +} + +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)); +} + +sal_uInt16 E3dExtrudeObj::GetObjIdentifier() const +{ + return E3D_EXTRUDEOBJ_ID; +} + +E3dExtrudeObj* E3dExtrudeObj::CloneSdrObject(SdrModel& rTargetModel) const +{ + return CloneHelper< E3dExtrudeObj >(rTargetModel); +} + +E3dExtrudeObj& E3dExtrudeObj::operator=(const E3dExtrudeObj& rObj) +{ + if( this == &rObj ) + return *this; + E3dCompoundObject::operator=(rObj); + + maExtrudePolygon = rObj.maExtrudePolygon; + + return *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 +{ + OUStringBuffer sName(SvxResId(STR_ObjNameSingulExtrude3d)); + + OUString aName(GetName()); + if (!aName.isEmpty()) + { + sName.append(' '); + sName.append('\''); + sName.append(aName); + sName.append('\''); + } + return sName.makeStringAndClear(); +} + +// Get the name of the object (plural) + +OUString E3dExtrudeObj::TakeObjNamePlural() const +{ + return SvxResId(STR_ObjNamePluralExtrude3d); +} + +bool E3dExtrudeObj::IsBreakObjPossible() +{ + return true; +} + +std::unique_ptr 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(GetExtrudeDepth())); + + aBackSide.transform(aTransform); + } + } + + if(aBackSide.count()) + { + // create PathObj + basegfx::B2DPolyPolygon aPoly = TransformToScreenCoor(aBackSide); + std::unique_ptr pPathObj(new SdrPathObj(getSdrModelFromSdrObject(), OBJ_PLIN, aPoly)); + + SfxItemSet aSet(GetObjectItemSet()); + aSet.Put(XLineStyleItem(css::drawing::LineStyle_SOLID)); + pPathObj->SetMergedItemSet(aSet); + + return std::unique_ptr(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..8636cfc2b --- /dev/null +++ b/svx/source/engine3d/float3d.cxx @@ -0,0 +1,2949 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +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"), GetFrameWeld())) + , m_xLbLight2(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor2"), GetFrameWeld())) + , m_xLbLight3(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor3"), GetFrameWeld())) + , m_xLbLight4(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor4"), GetFrameWeld())) + , m_xLbLight5(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor5"), GetFrameWeld())) + , m_xLbLight6(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor6"), GetFrameWeld())) + , m_xLbLight7(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor7"), GetFrameWeld())) + , m_xLbLight8(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor8"), GetFrameWeld())) + , m_xBtnLightColor(m_xBuilder->weld_button("colorbutton1")) + , m_xLbAmbientlight(new ColorListBox(m_xBuilder->weld_menu_button("ambientcolor"), 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_xBtnTexBlend(m_xBuilder->weld_toggle_button("texblend")) + , 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"), GetFrameWeld())) + , m_xBtnMatColor(m_xBuilder->weld_button("colorbutton3")) + , m_xLbMatEmission(new ColorListBox(m_xBuilder->weld_menu_button("illumcolor"), 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"), 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 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 aLink2 = LINK( this, Svx3DWin, SelectHdl ); + Link 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 aLink3 = LINK( this, Svx3DWin, ModifyMetricHdl ); + Link 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_xBtnTexBlend.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(*rAttrs.GetPool(), + svl::Items{}); + + 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(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(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(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(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 = mpRemember2DAttributes->GetItemState(nWhich, 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(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(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(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(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(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(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(m_xMtrMatSpecularIntensity->get_value(FieldUnit::PERCENT)); + rAttrs.Put(makeSvx3DMaterialSpecularIntensityItem(nValue2)); + } + else + rAttrs.InvalidateItem(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY); +} + +void Svx3DWin::Resize() +{ + if ( !IsFloatingMode() || + !GetFloatingWindow()->IsRollUp() ) + { + 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::ToggleButton&, 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 + SfxItemSet aSet( pModel->GetItemPool(), svl::Items{}); + + // 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 ) +{ + 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 pWin = VclPtr::Create( pBindings, this, _pParent ); + SetWindow(pWin); + + pWin->Initialize( pInfo ); +} + +Svx3DCtrlItem::Svx3DCtrlItem( sal_uInt16 _nId, + SfxBindings* _pBindings) : + SfxControllerItem( _nId, *_pBindings ) +{ +} + + +void Svx3DCtrlItem::StateChanged( 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::StateChanged(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 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..f553b4d0e --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + + +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)) + { + // 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()) + { + // 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()) + { + // 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) + { + 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +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..15da40d09 --- /dev/null +++ b/svx/source/engine3d/helperminimaldepth3d.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_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..37060f96e --- /dev/null +++ b/svx/source/engine3d/lathe3d.cxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// DrawContact section +std::unique_ptr E3dLatheObj::CreateObjectSpecificViewContact() +{ + return std::make_unique(*this); +} + +std::unique_ptr E3dLatheObj::CreateObjectSpecificProperties() +{ + return std::make_unique(*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() +{ +} + +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())); +} + +sal_uInt16 E3dLatheObj::GetObjIdentifier() const +{ + return E3D_LATHEOBJ_ID; +} + +E3dLatheObj* E3dLatheObj::CloneSdrObject(SdrModel& rTargetModel) const +{ + return CloneHelper< E3dLatheObj >(rTargetModel); +} + +E3dLatheObj& E3dLatheObj::operator=(const E3dLatheObj& rObj) +{ + if( this == &rObj ) + return *this; + E3dCompoundObject::operator=(rObj); + + maPolyPoly2D = rObj.maPolyPoly2D; + + return *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) + { + 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 +{ + OUStringBuffer sName(SvxResId(STR_ObjNameSingulLathe3d)); + + OUString aName(GetName()); + if (!aName.isEmpty()) + { + sName.append(' '); + sName.append('\''); + sName.append(aName); + sName.append('\''); + } + return sName.makeStringAndClear(); +} + +// Get the name of the object (plural) + +OUString E3dLatheObj::TakeObjNamePlural() const +{ + return SvxResId(STR_ObjNamePluralLathe3d); +} + +bool E3dLatheObj::IsBreakObjPossible() +{ + return true; +} + +std::unique_ptr E3dLatheObj::GetBreakObj() +{ + // create PathObj + basegfx::B3DPolyPolygon aLathePoly3D(basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(maPolyPoly2D)); + basegfx::B2DPolyPolygon aTransPoly(TransformToScreenCoor(aLathePoly3D)); + std::unique_ptr pPathObj(new SdrPathObj(getSdrModelFromSdrObject(), OBJ_PLIN, 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(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..eca597bb4 --- /dev/null +++ b/svx/source/engine3d/obj3d.cxx @@ -0,0 +1,625 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; + +std::unique_ptr E3dObject::CreateObjectSpecificProperties() +{ + return std::make_unique(*this); +} + +E3dObject::E3dObject(SdrModel& rSdrModel) +: SdrAttrObj(rSdrModel), + maLocalBoundVol(), + maTransformation(), + maFullTransform(), + mbTfHasChanged(true), + mbIsSelected(false) +{ + bIs3DObj = true; + bClosedObj = true; +} + +E3dObject::~E3dObject() +{ +} + +void E3dObject::SetSelected(bool bNew) +{ + if(mbIsSelected != bNew) + { + mbIsSelected = bNew; + } +} + +// Break, default implementations +bool E3dObject::IsBreakObjPossible() +{ + return false; +} + +std::unique_ptr E3dObject::GetBreakObj() +{ + return nullptr; +} + +SdrInventor E3dObject::GetObjInventor() const +{ + return SdrInventor::E3d; +} + +sal_uInt16 E3dObject::GetObjIdentifier() const +{ + return E3D_OBJECT_ID; +} + +// 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(rRef.X()), static_cast(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(rSize.Width()) * aEyeVol.getWidth() / static_cast(aRect.GetWidth()), + static_cast(-rSize.Height()) * aEyeVol.getHeight() / static_cast(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; + 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 (pUserCall != nullptr) 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 +{ + OUStringBuffer sName(SvxResId(STR_ObjNameSingulObj3d)); + + OUString aName(GetName()); + if (!aName.isEmpty()) + { + sName.append(' '); + sName.append('\''); + sName.append(aName); + sName.append('\''); + } + return sName.makeStringAndClear(); +} + +// Get the name of the object (plural) +OUString E3dObject::TakeObjNamePlural() const +{ + return SvxResId(STR_ObjNamePluralObj3d); +} + +E3dObject* E3dObject::CloneSdrObject(SdrModel& rTargetModel) const +{ + return CloneHelper< E3dObject >(rTargetModel); +} + +E3dObject& E3dObject::operator=(const E3dObject& rSource) +{ + if(this != &rSource) + { + // call parent + SdrAttrObj::operator=(rSource); + + // 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; + } + + return *this; +} + +SdrObjGeoData *E3dObject::NewGeoData() const +{ + return new E3DObjGeoData; +} + +void E3dObject::SaveGeoData(SdrObjGeoData& rGeo) const +{ + SdrAttrObj::SaveGeoData (rGeo); + + static_cast(rGeo).maLocalBoundVol = maLocalBoundVol; + static_cast(rGeo).maTransformation = maTransformation; +} + +void E3dObject::RestGeoData(const SdrObjGeoData& rGeo) +{ + maLocalBoundVol = static_cast(rGeo).maLocalBoundVol; + E3DModifySceneSnapRectUpdater aUpdater(this); + NbcSetTransform(static_cast(rGeo).maTransformation); + SdrAttrObj::RestGeoData (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, long nAngle, double sn, double cs) +{ + // So currently the glue points are defined relative to the scene aOutRect. + // Before turning the glue points 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 = basegfx::deg2rad(nAngle/100.0); + + basegfx::B3DHomMatrix aRotateZ; + aRotateZ.rotate(0.0, 0.0, fAngleInRad); + NbcSetTransform(aRotateZ * GetTransform()); + + SetRectsDirty(); // This forces a recalculation of all BoundRects + NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the glue points (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 E3dCompoundObject::CreateObjectSpecificProperties() +{ + return std::make_unique(*this); +} + +E3dCompoundObject::E3dCompoundObject(SdrModel& rSdrModel) +: E3dObject(rSdrModel) +{ +} + +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(Point(basegfx::fround(aPos2D.getX()), basegfx::fround(aPos2D.getY())), SdrHdlKind::BezierWeight)); + } + } + } + + const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly()); + + if(aPolyPolygon.count()) + { + rHdlList.AddHdl(std::make_unique(aPolyPolygon)); + } +} + +sal_uInt16 E3dCompoundObject::GetObjIdentifier() const +{ + return E3D_COMPOUNDOBJ_ID; +} + +void E3dCompoundObject::RecalcSnapRect() +{ + const uno::Sequence< beans::PropertyValue > aEmptyParameters; + drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters); + E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this); + maSnapRect = tools::Rectangle(); + + if(pRootScene) + { + // get VC of 3D candidate + const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact()); + + if(pVCOfE3D) + { + // get 3D primitive sequence + const drawinglayer::primitive3d::Primitive3DContainer xLocalSequence(pVCOfE3D->getViewIndependentPrimitive3DContainer()); + + if(!xLocalSequence.empty()) + { + // 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 CloneHelper< E3dCompoundObject >(rTargetModel); +} + +E3dCompoundObject& E3dCompoundObject::operator=(const E3dCompoundObject& rObj) +{ + if( this == &rObj ) + return *this; + E3dObject::operator=(rObj); + return *this; +} + +// convert given basegfx::B3DPolyPolygon to screen coor +basegfx::B2DPolyPolygon E3dCompoundObject::TransformToScreenCoor(const basegfx::B3DPolyPolygon& rCandidate) +{ + 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..5c617127b --- /dev/null +++ b/svx/source/engine3d/objfac3d.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 +#include +#include +#include +#include +#include +#include +#include +#include + +static bool bInit = false; + +E3dObjFactory::E3dObjFactory() +{ + if ( !bInit ) + { + SdrObjFactory::InsertMakeObjectHdl(LINK(this, E3dObjFactory, MakeObject)); + bInit = true; + } +} + +E3dObjFactory::~E3dObjFactory() +{ +} + +// Generate chart internal objects + +IMPL_STATIC_LINK( E3dObjFactory, MakeObject, SdrObjCreatorParams, aParams, SdrObject* ) +{ + if ( aParams.nInventor == SdrInventor::E3d ) + { + switch ( aParams.nObjIdentifier ) + { + case E3D_SCENE_ID: + return new E3dScene(aParams.rSdrModel); + case E3D_POLYGONOBJ_ID : + return new E3dPolygonObj(aParams.rSdrModel); + case E3D_CUBEOBJ_ID : + return new E3dCubeObj(aParams.rSdrModel); + case E3D_SPHEREOBJ_ID: + return new E3dSphereObj(aParams.rSdrModel); + case E3D_EXTRUDEOBJ_ID: + return new E3dExtrudeObj(aParams.rSdrModel); + case E3D_LATHEOBJ_ID: + return new E3dLatheObj(aParams.rSdrModel); + case E3D_COMPOUNDOBJ_ID: + return new E3dCompoundObject(aParams.rSdrModel); + } + } + 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..d8c1b5d0c --- /dev/null +++ b/svx/source/engine3d/polygn3d.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 +#include +#include +#include +#include +#include + +// DrawContact section +std::unique_ptr E3dPolygonObj::CreateObjectSpecificViewContact() +{ + return std::make_unique(*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 +} + +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() +{ +} + +sal_uInt16 E3dPolygonObj::GetObjIdentifier() const +{ + return E3D_POLYGONOBJ_ID; +} + +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 CloneHelper< E3dPolygonObj >(rTargetModel); +} + +E3dPolygonObj& E3dPolygonObj::operator=(const E3dPolygonObj& rObj) +{ + if( this == &rObj ) + return *this; + E3dCompoundObject::operator=(rObj); + + aPolyPoly3D = rObj.aPolyPoly3D; + aPolyNormals3D = rObj.aPolyNormals3D; + aPolyTexture2D = rObj.aPolyTexture2D; + bLineOnly = rObj.bLineOnly; + + return *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..66b134770 --- /dev/null +++ b/svx/source/engine3d/scene3d.cxx @@ -0,0 +1,909 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "helperminimaldepth3d.hxx" +#include +#include +#include +#include +#include +#include + +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(dynamic_cast< const E3dCompoundObject*>(pCandidate)) + { + // single 3d object, calc depth + const double fMinimalDepth(getMinimalDepthInViewCoordinates(static_cast< const E3dCompoundObject& >(*pCandidate))); + 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 E3dScene::CreateObjectSpecificProperties() +{ + return std::make_unique(*this); +} + + +// DrawContact section + +std::unique_ptr E3dScene::CreateObjectSpecificViewContact() +{ + return std::make_unique(*this); +} + + +E3dScene::E3dScene(SdrModel& rSdrModel) +: E3dObject(rSdrModel), + SdrObjList(), + aCamera(basegfx::B3DPoint(0.0, 0.0, 4.0), basegfx::B3DPoint()), + bDrawOnlySelected(false), + mbSkipSettingDirty(false) +{ + // Set defaults + SetDefaultAttributes(); +} + +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; +} + +sal_uInt16 E3dScene::GetObjIdentifier() const +{ + return E3D_SCENE_ID; +} + +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) +{ + SetRectsDirty(); + 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(GetProperties()).SetSceneItemsFromCamera(); + + SetRectsDirty(); + + // 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) + { + SetRectsDirty(); + } + + 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(dynamic_cast< const E3dScene*>(pObj)) + { + E3dScene* pScene = static_cast(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(dynamic_cast< const E3dCompoundObject*>(pObj)) + { + E3dCompoundObject* pCompound = static_cast(pObj); + + if(!pCompound->GetSelected()) + { + bRemoveObject = true; + } + } + + if(bRemoveObject) + { + NbcRemoveObject(pObj->GetOrdNum()); + a--; + SdrObject::Free(pObj); + } + } + } +} + +E3dScene* E3dScene::CloneSdrObject(SdrModel& rTargetModel) const +{ + return CloneHelper< E3dScene >(rTargetModel); +} + +E3dScene& E3dScene::operator=(const E3dScene& rSource) +{ + if(this != &rSource) + { + // call parent + E3dObject::operator=(rSource); + + // 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 + SetRectsDirty(); + } + + // copy local data + aCamera = rSource.aCamera; + aCameraSet = rSource.aCameraSet; + static_cast(GetProperties()).SetSceneItemsFromCamera(); + InvalidateBoundVolume(); + RebuildLists(); + ImpCleanup3DDepthMapper(); + GetViewContact().ActionChanged(); + } + + return *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->SetRectsDirty(); + } +} + +// 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(); +} + +SdrObjGeoData *E3dScene::NewGeoData() const +{ + return new E3DSceneGeoData; +} + +void E3dScene::SaveGeoData(SdrObjGeoData& rGeo) const +{ + E3dObject::SaveGeoData (rGeo); + + static_cast(rGeo).aCamera = aCamera; +} + +void E3dScene::RestGeoData(const SdrObjGeoData& rGeo) +{ + // #i94832# removed E3DModifySceneSnapRectUpdater here. + // It should not be needed, is already part of E3dObject::RestGeoData + E3dObject::RestGeoData (rGeo); + SetCamera (static_cast(rGeo).aCamera); +} + +// Something was changed in the style sheet, so change scene + +void E3dScene::Notify(SfxBroadcaster &rBC, const SfxHint &rHint) +{ + SetRectsDirty(); + E3dObject::Notify(rBC, rHint); +} + +void E3dScene::RotateScene (const Point& rRef, double sn, double cs) +{ + Point UpperLeft, LowerRight, Center, NewCenter; + + UpperLeft = aOutRect.TopLeft(); + LowerRight = aOutRect.BottomRight(); + + long dxOutRectHalf = labs(UpperLeft.X() - LowerRight.X()); + dxOutRectHalf /= 2; + long dyOutRectHalf = labs(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(Center.X() * cs - Center.Y() * sn) ); + NewCenter.setY( static_cast(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 +{ + OUStringBuffer sName(SvxResId(STR_ObjNameSingulScene3d)); + + OUString aName(GetName()); + if (!aName.isEmpty()) + { + sName.append(' '); + sName.append('\''); + sName.append(aName); + sName.append('\''); + } + return sName.makeStringAndClear(); +} + +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, long nAngle, double sn, double cs) +{ + // So currently the glue points are defined relative to the scene aOutRect. + // Before turning the glue points 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 = basegfx::deg2rad(nAngle/100.0); + + basegfx::B3DHomMatrix aRotation; + aRotation.rotate(0.0, 0.0, fAngleInRad); + NbcSetTransform(aRotation * GetTransform()); + + SetRectsDirty(); // This forces a recalculation of all BoundRects + NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the glue points (who still + // have coordinates relative to the + // original page) + SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect) + SetRectsDirty(); +} + +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(a3DIterator.Next()); + DBG_ASSERT(dynamic_cast< const E3dObject*>(pObj), "only 3D objects are allowed in scenes!"); + 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(); + bSnapRectDirty=true; + return true; +} + +bool E3dScene::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) +{ + tools::Rectangle aRect1; + rStat.TakeCreateRect(aRect1); + aRect1.Justify(); + NbcSetSnapRect(aRect1); + SetRectsDirty(); + 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::SetRectsDirty(bool bNotMyself, bool bRecursive) +{ + // call parent + E3dObject::SetRectsDirty(bNotMyself, bRecursive); + + for(size_t a = 0; a < GetObjCount(); ++a) + { + E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a)); + + if(pCandidate) + { + pCandidate->SetRectsDirty(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) + { + // 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..e5e6939c1 --- /dev/null +++ b/svx/source/engine3d/sphere3d.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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// DrawContact section +std::unique_ptr E3dSphereObj::CreateObjectSpecificViewContact() +{ + return std::make_unique(*this); +} + +std::unique_ptr E3dSphereObj::CreateObjectSpecificProperties() +{ + return std::make_unique(*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() +{ +} + +void E3dSphereObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault) +{ + // Set defaults + aCenter = rDefault.GetDefaultSphereCenter(); + aSize = rDefault.GetDefaultSphereSize(); +} + +sal_uInt16 E3dSphereObj::GetObjIdentifier() const +{ + return E3D_SPHEREOBJ_ID; +} + +// 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 CloneHelper< E3dSphereObj >(rTargetModel); +} + +E3dSphereObj& E3dSphereObj::operator=(const E3dSphereObj& rObj) +{ + if( this == &rObj ) + return *this; + E3dCompoundObject::operator=(rObj); + + aCenter = rObj.aCenter; + aSize = rObj.aSize; + + return *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 +{ + OUStringBuffer sName(SvxResId(STR_ObjNameSingulSphere3d)); + + OUString aName(GetName()); + if (!aName.isEmpty()) + { + sName.append(' '); + sName.append('\''); + sName.append(aName); + sName.append('\''); + } + return sName.makeStringAndClear(); +} + +// 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..1468fb0ff --- /dev/null +++ b/svx/source/engine3d/svx3ditems.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 +#include +#include +#include +#include +#include +#include + + +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(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(GetValue()); + return true; +} + +bool Svx3DNormalsKindItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + drawing::NormalsKind eVar; + if(!(rVal >>= eVar)) + return false; + SetValue(static_cast(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(GetValue()); + return true; +} + +bool Svx3DTextureProjectionXItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + drawing::TextureProjectionMode eVar; + if(!(rVal >>= eVar)) + return false; + SetValue(static_cast(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(GetValue()); + return true; +} + +bool Svx3DTextureProjectionYItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + drawing::TextureProjectionMode eVar; + if(!(rVal >>= eVar)) + return false; + SetValue(static_cast(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(GetValue()); + return true; +} + +bool Svx3DTextureKindItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + drawing::TextureKind eVar; + if(!(rVal >>= eVar)) + return false; + SetValue(static_cast(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(GetValue()); + return true; +} + +bool Svx3DTextureModeItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + drawing::TextureMode eVar; + if(!(rVal >>= eVar)) + return false; + SetValue(static_cast(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(GetValue()); + return true; +} + +bool Svx3DPerspectiveItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + drawing::ProjectionMode eVar; + if(!(rVal >>= eVar)) + return false; + SetValue(static_cast(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(GetValue()); + return true; +} + +bool Svx3DShadeModeItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + drawing::ShadeMode eVar; + if(!(rVal >>= eVar)) + return false; + SetValue(static_cast(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..77d94ab1c --- /dev/null +++ b/svx/source/engine3d/view3d.cxx @@ -0,0 +1,1599 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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) +: maObjects(), + mrView(rView), + mnCount(rView.GetMarkedObjectCount()), + mpPolygons(nullptr), + maFullOverlay() +{ + if(mnCount) + { + 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) + const drawinglayer::primitive2d::Primitive2DContainer& aNewSequence( + pObject->GetViewContact().getViewIndependentPrimitive2DContainer()); + maFullOverlay.append(aNewSequence); + } + } + } + } + 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. + if(!mrView.IsSolidDragging()) + { + 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, 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(aContent, 0.5)); + aContent = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparencePrimitive2D }; + + std::unique_ptr pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(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 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(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(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(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(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 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 && dynamic_cast< const E3dCompoundObject*>(pObj)) + { + // if the object is selected, but it's scene not, + // we need special handling + pScene = static_cast(pObj)->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 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(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(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(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(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(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(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( pObj) != nullptr) + { + const SfxItemSet& rSet = pObj->GetMergedItemSet(); + const SvxColorItem& rTextColorItem = rSet.Get(EE_CHAR_COLOR); + if(rTextColorItem.GetValue() == COL_BLACK) + { + //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) +{ + if(dynamic_cast( pObj) != nullptr) + { + 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(static_cast(pObj)->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( pObj ); + + if(pPath) + { + 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_Attribut 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) + { + // 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) + { + // 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(aRect.GetWidth()); + double fH = static_cast(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()) - F_PI2; + + 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(-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; aGetMarkedSdrObj(); + 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(aRot.getX() + 0.5), static_cast(-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(aRot.getX() + 0.5), static_cast(-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(aRot.getX() + 0.5), static_cast(-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(aRot.getX() + 0.5), static_cast(-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; aGetMarkedSdrObj(); + + 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(aRect.GetWidth()), static_cast(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(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 mvNeighbours; + + E3dDepthLayer() + : mpDown(nullptr) + { + } +}; + +} + +void E3dView::DoDepthArrange(E3dScene const * pScene, double fDepth) +{ + if(pScene && pScene->GetSubList() && pScene->GetSubList()->GetObjCount() > 1) + { + 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(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(nullptr != dynamic_cast< const E3dScene* >(pObj) && static_cast< E3dScene* >(pObj)->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(fW), static_cast(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 + long nOutMin = 0; + long nOutMax = 0; + long nMinLen = 0; + long nObjDst = 0; + 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(); + + 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; + + 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()); + long nMarkHgt = basegfx::fround(aR.getHeight()) - 1; + long nHgt = nMarkHgt + nObjDst * 2; + + if (nHgt < nMinLen) nHgt = nMinLen; + + long nY1 = basegfx::fround(aCenter.getY()) - (nHgt + 1) / 2; + 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()) + { + 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()) + { + // ALL selected objects are changed + const size_t nCount = GetMarkedObjectCount(); + + BegUndo(SvxResId(RID_SVX_3D_UNDO_BREAK_LATHE)); + for(size_t a=0; a(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(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) + { + const size_t nMarkCnt = GetMarkedObjectCount(); + bool bCoumpound = false; + bool b3DObject = false; + for(size_t nObjs = 0; (nObjs < nMarkCnt) && !bCoumpound; ++nObjs) + { + SdrObject *pObj = GetMarkedObjectByIndex(nObjs); + if(dynamic_cast< const E3dCompoundObject* >(pObj)) + bCoumpound = 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 && bCoumpound) + m_bGroupPossible = false; + + if(m_bUnGroupPossible && b3DObject) + m_bUnGroupPossible = false; + + if(m_bGrpEnterPossible && bCoumpound) + 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..7f0acf713 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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{}); + + 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 + SfxItemSet aDefaultSet(mpModel->GetItemPool(), svl::Items{}); + 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 + SfxItemSet aDefaultSet(mpModel->GetItemPool(), svl::Items{}); + aDefaultSet.Put(rAttr); + SetAttributes(aDefaultSet); + } +} + +double E3dView::GetDefaultCamPosZ() +{ + return static_cast(mpModel->GetItemPool().GetDefaultItem(SDRATTR_3DSCENE_DISTANCE).GetValue()); +} + +double E3dView::GetDefaultCamFocal() +{ + return static_cast(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..660af6adf --- /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 + +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 = sqrt(fXupVp * fXupVp + fYupVp * 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..b11e9770b --- /dev/null +++ b/svx/source/fmcomp/dbaexchange.cxx @@ -0,0 +1,628 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 from 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(-1); + if (static_cast(-1) == s_nFormat) + { + s_nFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"dbaccess.ColumnDescriptorTransfer\""); + OSL_ENSURE(static_cast(-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 += OUString(&cCommandType, 1); + 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, _rFlavor); + default: break; + } + if (nFormatId == getDescriptorFormatId()) + return SetAny( makeAny( 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)const_cast(_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 = sFieldDescription.getToken(0, cSeparator, nIdx).toInt32(); + _rFieldName = sFieldDescription.getToken(0, cSeparator, nIdx); + + return true; + } + + + ODataAccessObjectTransferable::ODataAccessObjectTransferable( + const OUString& _rDatasource + ,const sal_Int32 _nCommandType + ,const OUString& _rCommand + ) + { + construct(_rDatasource,OUString(),_nCommandType,_rCommand,nullptr,(CommandType::COMMAND == _nCommandType),_rCommand); + } + + ODataAccessObjectTransferable::ODataAccessObjectTransferable( + const OUString& _rDatasource + ,const sal_Int32 _nCommandType + ,const OUString& _rCommand + ,const Reference< XConnection >& _rxConnection) + { + OSL_ENSURE(_rxConnection.is(),"Wrong ctor 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( makeAny(m_aDescriptor.createPropertyValueSequence()) ); + + case SotClipboardFormatId::SBA_DATAEXCHANGE: + return SetString(m_sCompatibleObjectDescription, rFlavor); + 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 += OUString(&cTableMark, 1); + break; + case CommandType::QUERY: + m_sCompatibleObjectDescription += OUString(&cQueryMark, 1); + break; + case CommandType::COMMAND: + m_sCompatibleObjectDescription += OUString(&cQueryMark, 1); + // 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(-1); + if (static_cast(-1) == s_nFormat) + { + s_nFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"dbaccess.MultipleColumnDescriptorTransfer\""); + OSL_ENSURE(static_cast(-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( makeAny( 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..b60b026e6 --- /dev/null +++ b/svx/source/fmcomp/dbaobjectex.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 +#include +#include +#include +#include +#include +#include + + +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(const OUString& _rDatasourceOrLocation + ,const Reference< XContent>& _xContent) + { + m_aDescriptor.setDataSource(_rDatasourceOrLocation); + m_aDescriptor[DataAccessDescriptorProperty::Component] <<= _xContent; + } + + + SotClipboardFormatId OComponentTransferable::getDescriptorFormatId(bool _bExtractForm) + { + static SotClipboardFormatId s_nReportFormat = static_cast(-1); + static SotClipboardFormatId s_nFormFormat = static_cast(-1); + if ( _bExtractForm && static_cast(-1) == s_nFormFormat ) + { + s_nFormFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"dbaccess.FormComponentDescriptorTransfer\""); + OSL_ENSURE(static_cast(-1) != s_nFormFormat, "OComponentTransferable::getDescriptorFormatId: bad exchange id!"); + } + else if ( !_bExtractForm && static_cast(-1) == s_nReportFormat) + { + s_nReportFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"dbaccess.ReportComponentDescriptorTransfer\""); + OSL_ENSURE(static_cast(-1) != s_nReportFormat, "OComponentTransferable::getDescriptorFormatId: bad exchange id!"); + } + return _bExtractForm ? s_nFormFormat : s_nReportFormat; + } + + + void OComponentTransferable::AddSupportedFormats() + { + bool bForm = true; + try + { + Reference 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( makeAny( 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..68b4b3c53 --- /dev/null +++ b/svx/source/fmcomp/fmgridcl.cxx @@ -0,0 +1,2061 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 SetMenuItem(const OUString& rImgID, const OString &rID, Menu& rMenu, bool bDesignMode) +{ + Image aImage(StockImage::Yes, rImgID); + sal_uInt16 nID = rMenu.GetItemId(rID); + rMenu.SetItemImage(nID, aImage); + rMenu.EnableItem(nID, bDesignMode); +} + +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(GetParent())->GetModelColumnPos(nId); +} + +void FmGridHeader::notifyColumnSelect(sal_uInt16 nColumnId) +{ + sal_uInt16 nPos = GetModelColumnPos(nColumnId); + Reference< XIndexAccess > xColumns = static_cast(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(makeAny(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(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(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(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(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", makeAny(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&) + { + OSL_FAIL("FmGridHeader::ExecuteDrop: 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(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 aPossibleTypes; + std::vector aImgResId; + switch (nDataType) + { + case DataType::BIT: + case DataType::BOOLEAN: + aPossibleTypes.emplace_back(FM_COL_CHECKBOX); + aImgResId.emplace_back(RID_SVXBMP_CHECKBOX); + break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + aPossibleTypes.emplace_back(FM_COL_NUMERICFIELD); + aImgResId.emplace_back(RID_SVXBMP_NUMERICFIELD); + aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD); + aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD); + 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); + aPossibleTypes.emplace_back(FM_COL_NUMERICFIELD); + aImgResId.emplace_back(RID_SVXBMP_NUMERICFIELD); + break; + case DataType::TIMESTAMP: + aPossibleTypes.emplace_back("dateandtimefield"); + aImgResId.emplace_back(RID_SVXBMP_DATE_N_TIME_FIELDS); + aPossibleTypes.emplace_back(FM_COL_DATEFIELD); + aImgResId.emplace_back(RID_SVXBMP_DATEFIELD); + aPossibleTypes.emplace_back(FM_COL_TIMEFIELD); + aImgResId.emplace_back(RID_SVXBMP_TIMEFIELD); + aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD); + aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD); + break; + case DataType::DATE: + aPossibleTypes.emplace_back(FM_COL_DATEFIELD); + aImgResId.emplace_back(RID_SVXBMP_DATEFIELD); + aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD); + aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD); + break; + case DataType::TIME: + aPossibleTypes.emplace_back(FM_COL_TIMEFIELD); + aImgResId.emplace_back(RID_SVXBMP_TIMEFIELD); + aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD); + aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD); + break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + default: + aPossibleTypes.emplace_back(FM_COL_TEXTFIELD); + aImgResId.emplace_back(RID_SVXBMP_EDITBOX); + aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD); + aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD); + 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); + } + } + catch (const Exception&) + { + OSL_FAIL("FmGridHeader::ExecuteDrop: Exception occurred!"); + } + + 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)) + { + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/colsmenu.ui", ""); + VclPtr aInsertMenu(aBuilder.get_menu("menu")); + PopupMenu* pTypeMenu = aInsertMenu->GetPopupMenu(aInsertMenu->GetItemId("insert")); + pTypeMenu->ShowItem(pTypeMenu->GetItemId("dateandtimefield")); + std::vector::const_iterator iter; + std::vector::const_iterator imgiter; + for (iter = aPossibleTypes.begin(), imgiter = aImgResId.begin(); + iter != aPossibleTypes.end(); ++iter, ++imgiter) + { + SetMenuItem(*imgiter, *iter, *pTypeMenu, true); + } + if (pTypeMenu->Execute(this, m_pImpl->aDropPosPixel)) + sPreferredType = pTypeMenu->GetCurItemIdent(); + } + + 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, makeAny( OUString( sFieldName + sTimePostfix ) ) ); + + OUString sDatePostfix(SvxResId( RID_STR_POSTFIX_DATE)); + xSecondCol->setPropertyValue(FM_PROP_LABEL, makeAny( OUString( sFieldName + sDatePostfix ) ) ); + } + else + xCol->setPropertyValue(FM_PROP_LABEL, makeAny(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, makeAny(sFieldName)); + if ( xSecondCol.is() ) + xSecondCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(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, makeAny(sRealName)); + else + xCol->setPropertyValue(FM_PROP_NAME, makeAny(sRealName)); + } + } + else + xCol->setPropertyValue(FM_PROP_NAME, makeAny(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, makeAny(sDatasource)); + else + xForm->setPropertyValue(FM_PROP_URL, makeAny(sURL)); + } + + if (::comphelper::getString(xForm->getPropertyValue(FM_PROP_COMMAND)).isEmpty()) + { + xForm->setPropertyValue(FM_PROP_COMMAND, makeAny(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&) + { + OSL_FAIL("FmGridHeader::OnAsyncExecuteDrop: 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, PopupMenu& rMenu) +{ + bool bDesignMode = static_cast(GetParent())->IsDesignMode(); + + Reference< css::container::XIndexContainer > xCols(static_cast(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(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(makeAny(xColumn)); + } + + // insert position, always before the current column + sal_uInt16 nPos = GetModelColumnPos(nColId); + bool bMarked = nColId && static_cast(GetParent())->isColumnMarked(nColId); + + PopupMenu* pMenu = rMenu.GetPopupMenu(rMenu.GetItemId("insert")); + if (pMenu) + { + SetMenuItem(RID_SVXBMP_EDITBOX, FM_COL_TEXTFIELD, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_CHECKBOX, FM_COL_CHECKBOX, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_COMBOBOX, FM_COL_COMBOBOX, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_LISTBOX, FM_COL_LISTBOX, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_DATEFIELD, FM_COL_DATEFIELD, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_TIMEFIELD, FM_COL_TIMEFIELD, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_NUMERICFIELD, FM_COL_NUMERICFIELD, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_CURRENCYFIELD, FM_COL_CURRENCYFIELD, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_PATTERNFIELD, FM_COL_PATTERNFIELD, *pMenu, bDesignMode); + SetMenuItem(RID_SVXBMP_FORMATTEDFIELD, FM_COL_FORMATTEDFIELD, *pMenu, bDesignMode); + } + + if (pMenu && 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; + } + } + + PopupMenu* pControlMenu = rMenu.GetPopupMenu(rMenu.GetItemId("change")); + if (pControlMenu) + { + SetMenuItem(RID_SVXBMP_EDITBOX, FM_COL_TEXTFIELD"1", *pControlMenu, bDesignMode && (nColType != TYPE_TEXTFIELD)); + SetMenuItem(RID_SVXBMP_CHECKBOX, FM_COL_CHECKBOX"1", *pControlMenu, bDesignMode && (nColType != TYPE_CHECKBOX)); + SetMenuItem(RID_SVXBMP_COMBOBOX, FM_COL_COMBOBOX"1", *pControlMenu, bDesignMode && (nColType != TYPE_COMBOBOX)); + SetMenuItem(RID_SVXBMP_LISTBOX, FM_COL_LISTBOX"1", *pControlMenu, bDesignMode && (nColType != TYPE_LISTBOX)); + SetMenuItem(RID_SVXBMP_DATEFIELD, FM_COL_DATEFIELD"1", *pControlMenu, bDesignMode && (nColType != TYPE_DATEFIELD)); + SetMenuItem(RID_SVXBMP_TIMEFIELD, FM_COL_TIMEFIELD"1", *pControlMenu, bDesignMode && (nColType != TYPE_TIMEFIELD)); + SetMenuItem(RID_SVXBMP_NUMERICFIELD, FM_COL_NUMERICFIELD"1", *pControlMenu, bDesignMode && (nColType != TYPE_NUMERICFIELD)); + SetMenuItem(RID_SVXBMP_CURRENCYFIELD, FM_COL_CURRENCYFIELD"1", *pControlMenu, bDesignMode && (nColType != TYPE_CURRENCYFIELD)); + SetMenuItem(RID_SVXBMP_PATTERNFIELD, FM_COL_PATTERNFIELD"1", *pControlMenu, bDesignMode && (nColType != TYPE_PATTERNFIELD)); + SetMenuItem(RID_SVXBMP_FORMATTEDFIELD, FM_COL_FORMATTEDFIELD"1", *pControlMenu, bDesignMode && (nColType != TYPE_FORMATTEDFIELD)); + } + rMenu.EnableItem(rMenu.GetItemId("change"), bDesignMode && bMarked && xCols.is()); + } + else + rMenu.EnableItem(rMenu.GetItemId("change"), false); + + rMenu.EnableItem(rMenu.GetItemId("insert"), bDesignMode && xCols.is()); + rMenu.EnableItem(rMenu.GetItemId("delete"), bDesignMode && bMarked && xCols.is()); + rMenu.EnableItem(rMenu.GetItemId("column"), bDesignMode && bMarked && xCols.is()); + + PopupMenu* pShowColsMenu = rMenu.GetPopupMenu(rMenu.GetItemId("show")); + sal_uInt16 nHiddenCols = 0; + if (pShowColsMenu) + { + if (xCols.is()) + { + // check for hidden cols + Reference< css::beans::XPropertySet > xCurCol; + Any aHidden,aName; + for (sal_Int32 i=0; igetCount(); ++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); + pShowColsMenu->InsertItem(nHiddenCols + 1, ::comphelper::getString(aName), + MenuItemBits::NONE, OString(), nHiddenCols); + // the ID is arbitrary, but should be unique within the whole menu + } + ++nHiddenCols; + } + } + } + pShowColsMenu->EnableItem(pShowColsMenu->GetItemId("more"), xCols.is() && (nHiddenCols > 16)); + pShowColsMenu->EnableItem(pShowColsMenu->GetItemId("all"), 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.EnableItem(rMenu.GetItemId("hide"), bAllowHide); + + if (bMarked) + { + + SfxViewFrame* pCurrentFrame = SfxViewFrame::Current(); + SfxItemState eState = SfxItemState::UNKNOWN; + // 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 pItem; + eState = pCurrentFrame->GetBindings().QueryState(SID_FM_CTL_PROPERTIES, pItem); + + if (eState >= SfxItemState::DEFAULT && pItem != nullptr) + { + bool bChecked = dynamic_cast( pItem.get()) != nullptr && static_cast(pItem.get())->GetValue(); + rMenu.CheckItem("column", bChecked); + } + } + } +} + +namespace { + +enum InspectorAction { eOpenInspector, eCloseInspector, eUpdateInspector, eNone }; + +} + +void FmGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const PopupMenu& rMenu, sal_uInt16 nExecutionResult) +{ + Reference< css::container::XIndexContainer > xCols(static_cast(GetParent())->GetPeer()->getColumns()); + sal_uInt16 nPos = GetModelColumnPos(nColId); + + OUString aFieldType; + bool bReplace = false; + InspectorAction eInspectorAction = eNone; + + OString sExecutionResult = rMenu.GetCurItemIdent(); + if (sExecutionResult.isEmpty()) + { + PopupMenu* pMenu = rMenu.GetPopupMenu(rMenu.GetItemId("insert")); + if (pMenu) + sExecutionResult = pMenu->GetCurItemIdent(); + } + if (sExecutionResult.isEmpty()) + { + PopupMenu* pMenu = rMenu.GetPopupMenu(rMenu.GetItemId("change")); + if (pMenu) + sExecutionResult = pMenu->GetCurItemIdent(); + } + if (sExecutionResult.isEmpty()) + { + PopupMenu* pMenu = rMenu.GetPopupMenu(rMenu.GetItemId("show")); + if (pMenu) + sExecutionResult = pMenu->GetCurItemIdent(); + } + + if (sExecutionResult == "delete") + { + Reference< XInterface > xCol( + xCols->getByIndex(nPos), css::uno::UNO_QUERY); + xCols->removeByIndex(nPos); + ::comphelper::disposeComponent(xCol); + } + else if (sExecutionResult == "hide") + { + Reference< css::beans::XPropertySet > xCurCol( xCols->getByIndex(nPos), css::uno::UNO_QUERY); + xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny(true)); + } + else if (sExecutionResult == "column") + { + eInspectorAction = rMenu.IsItemChecked(rMenu.GetItemId("column")) ? eOpenInspector : eCloseInspector; + } + else if (sExecutionResult.startsWith(FM_COL_TEXTFIELD)) + { + if (sExecutionResult != FM_COL_TEXTFIELD) + bReplace = true; + aFieldType = FM_COL_TEXTFIELD; + } + else if (sExecutionResult.startsWith(FM_COL_COMBOBOX)) + { + if (sExecutionResult != FM_COL_COMBOBOX) + bReplace = true; + aFieldType = FM_COL_COMBOBOX; + } + else if (sExecutionResult.startsWith(FM_COL_LISTBOX)) + { + if (sExecutionResult != FM_COL_LISTBOX) + bReplace = true; + aFieldType = FM_COL_LISTBOX; + } + else if (sExecutionResult.startsWith(FM_COL_CHECKBOX)) + { + if (sExecutionResult != FM_COL_CHECKBOX) + bReplace = true; + aFieldType = FM_COL_CHECKBOX; + } + else if (sExecutionResult.startsWith(FM_COL_DATEFIELD)) + { + if (sExecutionResult != FM_COL_DATEFIELD) + bReplace = true; + aFieldType = FM_COL_DATEFIELD; + } + else if (sExecutionResult.startsWith(FM_COL_TIMEFIELD)) + { + if (sExecutionResult != FM_COL_TIMEFIELD) + bReplace = true; + aFieldType = FM_COL_TIMEFIELD; + } + else if (sExecutionResult.startsWith(FM_COL_NUMERICFIELD)) + { + if (sExecutionResult != FM_COL_NUMERICFIELD) + bReplace = true; + aFieldType = FM_COL_NUMERICFIELD; + } + else if (sExecutionResult.startsWith(FM_COL_CURRENCYFIELD)) + { + if (sExecutionResult != FM_COL_CURRENCYFIELD) + bReplace = true; + aFieldType = FM_COL_CURRENCYFIELD; + } + else if (sExecutionResult.startsWith(FM_COL_PATTERNFIELD)) + { + if (sExecutionResult != FM_COL_PATTERNFIELD) + bReplace = true; + aFieldType = FM_COL_PATTERNFIELD; + } + else if (sExecutionResult.startsWith(FM_COL_FORMATTEDFIELD)) + { + if (sExecutionResult != FM_COL_FORMATTEDFIELD) + bReplace = true; + aFieldType = FM_COL_FORMATTEDFIELD; + } + else if (sExecutionResult == "more") + { + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr pDlg(pFact->CreateFmShowColsDialog(GetFrameWeld())); + pDlg->SetColumns(xCols); + pDlg->Execute(); + } + else if (sExecutionResult == "all") + { + // just iterate through all the cols ... + Reference< css::beans::XPropertySet > xCurCol; + for (sal_Int32 i=0; igetCount(); ++i) + { + xCurCol.set(xCols->getByIndex(i), css::uno::UNO_QUERY); + xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny(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 (nExecutionResult>0 && nExecutionResult<=16) + { // it was a "show column/" command (there are at most 16 such items) + // search the nExecutionResult'th hidden col + Reference< css::beans::XPropertySet > xCurCol; + for (sal_Int32 i=0; igetCount() && 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, makeAny(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, makeAny( 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, makeAny( sLabel ) ); + xNewCol->setPropertyValue( FM_PROP_NAME, makeAny( sLabel ) ); + + factory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xNewCol ); + + xCols->insertByIndex( nPos, makeAny( 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 ) + { + 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 + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/colsmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + + // let derivatives modify the menu + PreExecuteColumnContextMenu( nColId, *aContextMenu ); + aContextMenu->RemoveDisabledEntries( true, true ); + + // execute the menu + sal_uInt16 nResult = aContextMenu->Execute( this, _rPreferredPos ); + + // let derivatives handle the result + PostExecuteColumnContextMenu( nColId, *aContextMenu, nResult ); +} + +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 xSet(evt.Source,UNO_QUERY); + if (xRow.is() && (::cppu::any2bool(xSet->getPropertyValue(FM_PROP_ISNEW))|| CompareBookmark(getDataSource()->getBookmark(), xRow->GetBookmark()))) + { + 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) + { + 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; igetCount(); ++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(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&) + { + OSL_FAIL("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 + 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 aDeletedRows; + SetUpdateMode( false ); + try + { + aDeletedRows = xDeleteThem->deleteRows(aBookmarks); + } + catch(SQLException&) + { + } + SetUpdateMode( true ); + + // how many rows are deleted? + sal_Int32 nDeletedRows = static_cast(std::count_if(aDeletedRows.begin(), aDeletedRows.end(), + [](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(aDeletedRows.begin(), aDeletedRows.end(), 0); + if (pRow != aDeletedRows.end()) + { + auto i = static_cast(std::distance(aDeletedRows.begin(), 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 : 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()->IsModified()) + { + 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 FmGridControl::imp_CreateHeaderBar(BrowseBox* pParent) +{ + DBG_ASSERT( pParent == this, "FmGridControl::imp_CreateHeaderBar: parent?" ); + return VclPtr::Create( pParent ); +} + +void FmGridControl::markColumn(sal_uInt16 nId) +{ + if (GetHeaderBar() && m_nMarkedColumnId != nId) + { + // 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; +} + +long FmGridControl::QueryMinimumRowHeight() +{ + long const nMinimalLogicHeight = 20; // 0.2 cm + 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() ) + { + try + { + sal_Int32 nUnzoomedPixelHeight = CalcReverseZoom( GetDataRowHeight() ); + Any aProperty = makeAny( static_cast(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(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(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(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(nFieldPos) ); + return; + } + } + + // the control type is determined by the ColumnServiceName + static const char s_sPropColumnServiceName[] = "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) +{ + 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 bAllSuccessfull = 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 + bAllSuccessfull = false; + } + } + catch(Exception&) + { + OSL_FAIL("FmGridControl::selectBookmarks: could not move to one of the bookmarks!"); + return false; + } + + return bAllSuccessfull; +} + +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. + long nIdx = FirstSelectedRow(); + while (nIdx != BROWSER_ENDOFSELECTION) + { + // (we misuse the bookmarks array for this ...) + pBookmarks[i++] <<= static_cast(nIdx); + nIdx = NextSelectedRow(); + } + DBG_ASSERT(i == nSelectedRows, "FmGridControl::DeleteSelectedRows : could not collect the row indices !"); + + for (i=0; iSetState(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 xIndex = _pPeer->getColumns(); + if ( xIndex.is() && xIndex->getCount() > _nPosition ) + { + Reference 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( ::vcl::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const +{ + OUString sRetText; + switch( _eObjType ) + { + case ::vcl::BBTYPE_BROWSEBOX: + if ( GetPeer() ) + { + Reference xProp(GetPeer()->getColumns(),UNO_QUERY); + if ( xProp.is() ) + xProp->getPropertyValue(FM_PROP_NAME) >>= sRetText; + } + break; + case ::vcl::BBTYPE_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( ::vcl::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const +{ + OUString sRetText; + switch( _eObjType ) + { + case ::vcl::BBTYPE_BROWSEBOX: + if ( GetPeer() ) + { + Reference 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 ::vcl::BBTYPE_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(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) + { + // BEFORE calling the select at the SelectionSupplier! + m_nCurrentSelectedColumn = nSelectedColumn; + + if (!m_bSelecting) + { + 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(makeAny(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..400e28e8b --- /dev/null +++ b/svx/source/fmcomp/fmgridif.cxx @@ -0,0 +1,2764 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(rFont.GetFontSize().Height()); + aFD.Width = static_cast(rFont.GetFontSize().Width()); + aFD.Family = static_cast(rFont.GetFamilyType()); + aFD.CharSet = rFont.GetCharSet(); + aFD.Pitch = static_cast(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(rFont.GetUnderline()); + aFD.Strikeout = static_cast(rFont.GetStrikeout()); + aFD.Orientation = 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(rDescr.Family) ); + aFont.SetCharSet( static_cast(rDescr.CharSet) ); + aFont.SetPitch( static_cast(rDescr.Pitch) ); + aFont.SetWidthType( vcl::unohelper::ConvertFontWidth( rDescr.CharacterWidth ) ); + aFont.SetWeight( vcl::unohelper::ConvertFontWeight( rDescr.Weight ) ); + aFont.SetItalic( static_cast(rDescr.Slant) ); + aFont.SetUnderline( static_cast<::FontLineStyle>(rDescr.Underline) ); + aFont.SetStrikeout( static_cast<::FontStrikeout>(rDescr.Strikeout) ); + aFont.SetOrientation( static_cast(rDescr.Orientation) ); + aFont.SetKerning( static_cast(rDescr.Kerning) ); + aFont.SetWordLineMode( rDescr.WordLineMode ); + return aFont; +} + +FmXModifyMultiplexer::FmXModifyMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex ) + :OWeakSubObject( rSource ) + ,OInterfaceContainerHelper2( _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 ) + ,OInterfaceContainerHelper2( _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::OInterfaceIteratorHelper2 aIter(*this); + while ( bResult && aIter.hasMoreElements() ) + bResult = static_cast< XUpdateListener* >( 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 ) + ,OInterfaceContainerHelper2( _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 ) + ,OInterfaceContainerHelper2( _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 ) + ,OInterfaceContainerHelper2( _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) + :UnoControl() + ,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_CALL FmXGridControl::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +// 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 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() +{ + 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; +} + + +FmXGridPeer* FmXGridControl::imp_CreatePeer(vcl::Window* pParent) +{ + 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()) + { + 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::getUnoTunnelImplementation(rParentPeer); + if (pParent) + pParentWin = pParent->GetWindow().get(); + } + + 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::getUnoTunnelImplementation(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(); +} + + +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; + + // --- --- + { + 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(maAccessibleContext, UNO_QUERY)); + maAccessibleContext.clear(); + + // prepare firing an event + aModeChangeEvent.Source = *this; + aModeChangeEvent.NewMode = mbDesignMode ? OUStringLiteral( "design" ) : OUStringLiteral( "alive" ); + } + + // --- --- + 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::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 SAL_CALL FmXGridControl::getSupportedModes() +{ + Reference< css::util::XModeSelector > xPeer(getPeer(), UNO_QUERY); + return xPeer.is() ? xPeer->getSupportedModes() : css::uno::Sequence(); +} + + +sal_Bool SAL_CALL FmXGridControl::supportsMode(const OUString& Mode) +{ + Reference< css::util::XModeSelector > xPeer(getPeer(), UNO_QUERY); + return xPeer.is() && xPeer->supportsMode(Mode); +} + +// 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 FmXGridPeer::imp_CreateControl(vcl::Window* pParent, WinBits nStyle) +{ + return VclPtr::Create(m_xContext, pParent, this, nStyle); +} + + +void FmXGridPeer::Create(vcl::Window* pParent, WinBits nStyle) +{ + VclPtr 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 > const & aColumns = pGrid->GetColumns(); + + Sequence 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; iGetModelColumnPos(pGrid->GetColumnIdFromViewPos(static_cast(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 > 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(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(xFieldContent->getLong()); break; + case TypeClass_UNSIGNED_SHORT : pReturnArray[i] <<= static_cast(xFieldContent->getShort()); break; + case TypeClass_UNSIGNED_LONG : pReturnArray[i] <<= static_cast(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 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(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::OInterfaceIteratorHelper2 aIter(m_aUpdateListeners); + bool bCancel = false; + while (aIter.hasMoreElements() && !bCancel) + if ( !static_cast< XUpdateListener* >( 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 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 OUStringLiteral 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; ihasPropertyByName( 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 OUStringLiteral 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(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(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 pWin = GetWindow(); + if (pWin) + static_cast(pWin.get())->SetDesignMode(bOn); + } + + if (bOn) + DisConnectFromDispatcher(); + else + UpdateDispatches(); // will connect if not already connected and just update else +} + + +sal_Bool FmXGridPeer::isDesignMode() +{ + VclPtr pWin = GetWindow(); + if (pWin) + return static_cast(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(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(nWidth), static_cast(::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(::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(nWidth), static_cast(::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(pGrid->GetModelColCount())) + return; + + pGrid->RemoveColumn(pGrid->GetColumnIdFromModelPos(static_cast(::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(::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 > 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(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(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(::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( ::comphelper::getINT32(Value) ); + pGrid->SetBackground( aColor ); + pGrid->SetControlBackground( aColor ); + } + } + else if ( PropertyName == FM_PROP_TEXTCOLOR ) + { + if ( bVoid ) + { + pGrid->SetControlForeground(); + } + else + { + ::Color aColor( ::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 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(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); + VCLXWindow::dispose(); + + // 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(); + setRowSet(Reference< XRowSet > ()); +} + +// 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) + { + 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) + { + 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) + { + 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(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(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::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(_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 FmXGridPeer::getSupportedModes() +{ + static css::uno::Sequence const aModes + { + "DataMode", + "FilterMode" + }; + return aModes; +} + + +sal_Bool FmXGridPeer::supportsMode(const OUString& Mode) +{ + css::uno::Sequence 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(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(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()) + { + 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(this)); + } + + // we are the master of the chain's first interceptor + m_xFirstDispatchInterceptor = _xInterceptor; + m_xFirstDispatchInterceptor->setMasterDispatchProvider(static_cast(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(Reference< css::frame::XDispatchProvider >::query(xSlave)); + else + // it's the first interceptor of the chain, set ourself as slave + xMaster->setSlaveDispatchProvider(static_cast(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(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 !"); + + Sequence< css::util::URL>& aUrls = getSupportedURLs(); + + const std::vector& 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(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 makeAny(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& FmXGridPeer::getSupportedGridSlots() +{ + static const std::vector 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 char* 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 = OUString::createFromAscii(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 : 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; iremoveStatusListener(static_cast(this), *pSupportedURLs); + m_pDispatchers[i] = xNewDispatch; + if (m_pDispatchers[i].is()) + m_pDispatchers[i]->addStatusListener(static_cast(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; iaddStatusListener(static_cast(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; iremoveStatusListener(static_cast(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& aSupported = getSupportedGridSlots(); + for (size_t i=0; i& aUrls = getSupportedURLs(); + const css::util::URL* pUrls = aUrls.getConstArray(); + + const std::vector& aSlots = getSupportedGridSlots(); + + DBG_ASSERT(static_cast(aSlots.size()) == aUrls.getLength(), "FmXGridPeer::OnExecuteGridSlot : inconsistent data returned by getSupportedURLs/getSupportedGridSlots!"); + + for (size_t i=0; iComplete == 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..cc02e1a3a --- /dev/null +++ b/svx/source/fmcomp/gridcell.cxx @@ -0,0 +1,4634 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +const char INVALIDTEXT[] = "###"; +const char OBJECTTEXT[] = ""; + + +//= 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(nTypeId); + if (xField != m_xField) + { + // initial setting + m_xField = xField; + xField->getPropertyValue(FM_PROP_FORMATKEY) >>= m_nFormatKey; + m_nFieldPos = static_cast(_nFieldPos); + m_bReadOnly = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISREADONLY)); + m_bAutoValue = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_AUTOINCREMENT)); + m_nFieldType = static_cast(::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 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(static_cast(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, makeAny( 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(m_pCell.get())) + pCell->Update(); + else if (pRow && pRow->IsValid() && m_nFieldPos >= 0 && m_pCell.is() && pRow->HasField(m_nFieldPos)) + { + dynamic_cast(*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( 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( 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( 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 ) + || ( static_cast< vcl::Window& >( rDev ).IsEnabled() ); + + FmXDataCell* pDataCell = dynamic_cast( 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 ( dynamic_cast( m_pCell.get() ) != nullptr ) + static_cast< FmXFilterCell* >( m_pCell.get() )->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 ) +{ + vcl::Window* pWindows[] = { m_pPainter, m_pWindow }; + + if (_eInitWhat & InitWindowFacet::WritingMode) + { + for (vcl::Window* pWindow : pWindows) + { + if (pWindow) + pWindow->EnableRTL(rParent.IsRTLEnabled()); + } + } + + if (_eInitWhat & InitWindowFacet::Font) + { + for (vcl::Window* pWindow : pWindows) + { + if (!pWindow) + continue; + + pWindow->SetZoom(rParent.GetZoom()); + + const StyleSettings& rStyleSettings = pWindow->GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetTransparent(isTransparent()); + + if (rParent.IsControlFont()) + { + pWindow->SetControlFont(rParent.GetControlFont()); + aFont.Merge(rParent.GetControlFont()); + } + else + pWindow->SetControlFont(); + + pWindow->SetZoomedPointFont(*pWindow, aFont); // FIXME RenderContext + } + } + + if ((_eInitWhat & InitWindowFacet::Font) || (_eInitWhat & InitWindowFacet::Foreground)) + { + Color aTextColor(rParent.IsControlForeground() ? rParent.GetControlForeground() : rParent.GetTextColor()); + + bool bTextLineColor = rParent.IsTextLineColor(); + Color aTextLineColor(rParent.GetTextLineColor()); + + for (vcl::Window* 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) + { + if (rParent.IsControlBackground()) + { + Color aColor(rParent.GetControlBackground()); + for (vcl::Window* pWindow : pWindows) + { + if (pWindow) + { + if (isTransparent()) + pWindow->SetBackground(); + else + { + pWindow->SetBackground(aColor); + pWindow->SetControlBackground(aColor); + } + pWindow->SetFillColor(aColor); + } + } + } + else + { + if (m_pPainter) + { + if (isTransparent()) + m_pPainter->SetBackground(); + else + m_pPainter->SetBackground(rParent.GetBackground()); + m_pPainter->SetFillColor(rParent.GetFillColor()); + } + + if (m_pWindow) + { + if (isTransparent()) + m_pWindow->SetBackground(rParent.GetBackground()); + else + m_pWindow->SetFillColor(rParent.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() ) + { + Edit* pEditWindow = dynamic_cast< Edit* >( m_pWindow.get() ); + if ( pEditWindow ) + { + bool bReadOnly = m_rColumn.IsReadOnly(); + if ( !bReadOnly ) + { + _rxModel->getPropertyValue( i_bReadOnly ? OUString(FM_PROP_READONLY) : OUString(FM_PROP_ISREADONLY)) >>= bReadOnly; + } + static_cast< Edit* >( m_pWindow.get() )->SetReadOnly( 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( vcl::Window& 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 ) + { + 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 ) +{ + if ( m_pPainter->GetParent() == &_rDev ) + { + m_pPainter->SetPaintTransparent( true ); + m_pPainter->SetBackground( ); + m_pPainter->SetControlBackground( _rDev.GetFillColor() ); + m_pPainter->SetControlForeground( _rDev.GetTextColor() ); + m_pPainter->SetTextColor( _rDev.GetTextColor() ); + m_pPainter->SetTextFillColor( _rDev.GetTextColor() ); + + vcl::Font aFont( _rDev.GetFont() ); + aFont.SetTransparent( true ); + m_pPainter->SetFont( aFont ); + + m_pPainter->SetPosSizePixel( _rRect.TopLeft(), _rRect.GetSize() ); + m_pPainter->Show(); + m_pPainter->PaintImmediately(); + m_pPainter->SetParentUpdateMode( false ); + m_pPainter->Hide(); + m_pPainter->SetParentUpdateMode( true ); + } + else + { + m_pPainter->SetSizePixel( _rRect.GetSize() ); + m_pPainter->Draw( &_rDev, _rRect.TopLeft(), DrawFlags::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(*m_pWindow).SetMaxTextLen(_nMaxLen); + if (m_pPainter) + dynamic_cast(*m_pPainter).SetMaxTextLen(_nMaxLen); +} + +DbTextField::DbTextField(DbGridColumn& _rColumn) + :DbLimitedLengthField(_rColumn) + ,m_bIsSimpleEdit( true ) +{ +} + + +DbTextField::~DbTextField( ) +{ + m_pPainterImplementation.reset(); + m_pEdit.reset(); +} + + +void DbTextField::Init( vcl::Window& rParent, const Reference< XRowSet >& xCursor) +{ + sal_Int16 nAlignment = m_rColumn.SetAlignmentFromModel(-1); + + Reference< XPropertySet > xModel( m_rColumn.getModel() ); + + WinBits nStyle = WB_LEFT; + switch (nAlignment) + { + case awt::TextAlign::RIGHT: + nStyle = WB_RIGHT; + break; + + case awt::TextAlign::CENTER: + nStyle = WB_CENTER; + break; + } + + // is this a multi-line field? + bool bIsMultiLine = false; + try + { + if ( xModel.is() ) + { + OSL_VERIFY( xModel->getPropertyValue( FM_PROP_MULTILINE ) >>= bIsMultiLine ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + OSL_FAIL( "DbTextField::Init: caught an exception while determining the multi-line capabilities!" ); + } + + m_bIsSimpleEdit = !bIsMultiLine; + if ( bIsMultiLine ) + { + m_pWindow = VclPtr::Create( &rParent, nStyle ); + m_pEdit.reset(new MultiLineEditImplementation( *static_cast< MultiLineTextCell* >( m_pWindow.get() ) )); + + m_pPainter = VclPtr::Create( &rParent, nStyle ); + m_pPainterImplementation.reset(new MultiLineEditImplementation( *static_cast< MultiLineTextCell* >( m_pPainter.get() ) )); + } + else + { + m_pWindow = VclPtr::Create( &rParent, nStyle ); + m_pEdit.reset(new EditImplementation( *static_cast< Edit* >( m_pWindow.get() ) )); + + m_pPainter = VclPtr::Create( &rParent, nStyle ); + m_pPainterImplementation.reset(new EditImplementation( *static_cast< Edit* >( m_pPainter.get() ) )); + } + + if ( WB_LEFT == nStyle ) + { + // 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, Color** /*ppColor*/) +{ + if (!_rxField.is()) + return OUString(); + + const css::uno::Reference 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 ( EDIT_NOLIMIT != nMaxTextLen && sText.getLength() > nMaxTextLen ) + { + sal_Int32 nDiff = sText.getLength() - nMaxTextLen; + sText = sText.replaceAt(sText.getLength() - nDiff,nDiff, OUString()); + } + + + 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 ( EDIT_NOLIMIT != nMaxTextLen ) + { + 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, makeAny( 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( vcl::Window& rParent, const Reference< XRowSet >& xCursor) +{ + sal_Int16 nAlignment = m_rColumn.SetAlignmentFromModel(-1); + + Reference< css::beans::XPropertySet > xUnoModel = m_rColumn.getModel(); + + switch (nAlignment) + { + case css::awt::TextAlign::RIGHT: + m_pWindow = VclPtr::Create( &rParent, WB_RIGHT ); + m_pPainter = VclPtr::Create( &rParent, WB_RIGHT ); + break; + + case css::awt::TextAlign::CENTER: + m_pWindow = VclPtr::Create( &rParent, WB_CENTER ); + m_pPainter = VclPtr::Create( &rParent, WB_CENTER ); + break; + default: + m_pWindow = VclPtr::Create( &rParent, WB_LEFT ); + m_pPainter = VclPtr::Create( &rParent, WB_LEFT ); + + // Everything just so that the selection goes from right to left when getting focus + AllSettings aSettings = m_pWindow->GetSettings(); + StyleSettings aStyleSettings = aSettings.GetStyleSettings(); + aStyleSettings.SetSelectionOptions( + aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst); + aSettings.SetStyleSettings(aStyleSettings); + m_pWindow->SetSettings(aSettings); + } + + implAdjustGenericFieldSetting( xUnoModel ); + + static_cast< FormattedField* >( m_pWindow.get() )->SetStrictFormat( false ); + static_cast< FormattedField* >( m_pPainter.get() )->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* pImplmentation = comphelper::getUnoTunnelImplementation(m_xSupplier); + if (pImplmentation) + pFormatterUsed = pImplmentation->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 = static_cast(m_pWindow.get())->StandardFormatter(); + DBG_ASSERT(pFormatterUsed != nullptr, "DbFormattedField::Init : no standard formatter given by the numeric field !"); + } + // ... and a standard key + if (nFormatKey == -1) + nFormatKey = 0; + + static_cast(m_pWindow.get())->SetFormatter(pFormatterUsed); + static_cast(m_pPainter.get())->SetFormatter(pFormatterUsed); + + static_cast(m_pWindow.get())->SetFormatKey(nFormatKey); + static_cast(m_pPainter.get())->SetFormatKey(nFormatKey); + + static_cast(m_pWindow.get())->TreatAsNumber(m_rColumn.IsNumeric()); + static_cast(m_pPainter.get())->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); + static_cast(m_pWindow.get())->SetMinValue(dMin); + static_cast(m_pPainter.get())->SetMinValue(dMin); + bClearMin = false; + } + } + if (bClearMin) + { + static_cast(m_pWindow.get())->ClearMinValue(); + static_cast(m_pPainter.get())->ClearMinValue(); + } + bool bClearMax = true; + if (::comphelper::hasProperty(FM_PROP_EFFECTIVE_MAX, xUnoModel)) + { + Any aMin( xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_MAX)); + if (aMin.getValueType().getTypeClass() != TypeClass_VOID) + { + DBG_ASSERT(aMin.getValueType().getTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid max value !"); + double dMin = ::comphelper::getDouble(aMin); + static_cast(m_pWindow.get())->SetMaxValue(dMin); + static_cast(m_pPainter.get())->SetMaxValue(dMin); + bClearMax = false; + } + } + if (bClearMax) + { + static_cast(m_pWindow.get())->ClearMaxValue(); + static_cast(m_pPainter.get())->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()) + { + static_cast(m_pWindow.get())->SetDefaultValue(::comphelper::getDouble(aDefault)); + static_cast(m_pPainter.get())->SetDefaultValue(::comphelper::getDouble(aDefault)); + } + else + { + OUString sConverted; + Color* pDummy; + pFormatterUsed->GetOutputString(::comphelper::getDouble(aDefault), 0, sConverted, &pDummy); + static_cast(m_pWindow.get())->SetDefaultText(sConverted); + static_cast(m_pPainter.get())->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)) + { + static_cast(m_pWindow.get())->SetDefaultValue(dVal); + static_cast(m_pPainter.get())->SetDefaultValue(dVal); + } + } + else + { + static_cast(m_pWindow.get())->SetDefaultText(sDefault); + static_cast(m_pPainter.get())->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< FormattedField* >( 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< FormattedField* >( m_pWindow.get() )->SetFormatKey( nNewKey ); + if (m_pPainter) + static_cast< FormattedField* >( m_pPainter.get() )->SetFormatKey( nNewKey ); + } + else + { + DbLimitedLengthField::_propertyChanged( _rEvent ); + } +} + + +OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, Color** ppColor) +{ + // no color specification by default + if (ppColor != nullptr) + *ppColor = nullptr; + + // NULL value -> empty text + if (!_rxField.is()) + return OUString(); + + 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; + static_cast(m_pPainter.get())->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; + static_cast(m_pPainter.get())->SetTextFormatted(aText); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } + + aText = m_pPainter->GetText(); + if (ppColor != nullptr) + *ppColor = static_cast(m_pPainter.get())->GetLastOutputColor(); + + return aText; +} + + +void DbFormattedField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/) +{ + try + { + FormattedField* pFormattedWindow = static_cast(m_pWindow.get()); + if (!_rxField.is()) + { // NULL value -> empty text + m_pWindow->SetText(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()) + m_pWindow->SetText(OUString()); + else + pFormattedWindow->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()); + + pFormattedWindow->SetTextFormatted( sText ); + pFormattedWindow->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } +} + + +void DbFormattedField::updateFromModel( Reference< XPropertySet > _rxModel ) +{ + OSL_ENSURE( _rxModel.is() && m_pWindow, "DbFormattedField::updateFromModel: invalid call!" ); + + FormattedField* pFormattedWindow = static_cast< FormattedField* >( m_pWindow.get() ); + + OUString sText; + Any aValue = _rxModel->getPropertyValue( FM_PROP_EFFECTIVE_VALUE ); + if ( !aValue.hasValue() || (aValue >>= sText) ) + { // our effective value is transferred as string + pFormattedWindow->SetTextFormatted( sText ); + pFormattedWindow->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) ); + } + else + { + double dValue = 0; + aValue >>= dValue; + pFormattedWindow->SetValue(dValue); + } +} + + +bool DbFormattedField::commitControl() +{ + Any aNewVal; + FormattedField& rField = *static_cast(m_pWindow.get()); + DBG_ASSERT(&rField == m_pWindow, "DbFormattedField::commitControl : can't work with a window other than my own !"); + if (m_rColumn.IsNumeric()) + { + if (!rField.GetText().isEmpty()) + aNewVal <<= rField.GetValue(); + // an empty string is passed on as void by default, to start with + } + else + aNewVal <<= rField.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( vcl::Window& rParent, const Reference< XRowSet >& xCursor ) +{ + setTransparent( true ); + + m_pWindow = VclPtr::Create( &rParent ); + m_pPainter = VclPtr::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() )->GetBox().EnableTriState( bTristate ); + static_cast< CheckBoxControl* >( m_pPainter.get() )->GetBox().EnableTriState( bTristate ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } + + DbCellControl::Init( rParent, xCursor ); +} + + +CellControllerRef DbCheckBox::CreateController() const +{ + return new CheckBoxCellController(static_cast(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->GetBox().SetState(eState); +} + + +void DbCheckBox::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/) +{ + lcl_setCheckBoxState( _rxField, static_cast(m_pWindow.get()) ); +} + + +void DbCheckBox::PaintFieldToCell(OutputDevice& rDev, const tools::Rectangle& rRect, + const Reference< css::sdb::XColumn >& _rxField, + const Reference< XNumberFormatter >& xFormatter) +{ + lcl_setCheckBoxState( _rxField, static_cast(m_pPainter.get()) ); + DbCellControl::PaintFieldToCell( rDev, rRect, _rxField, xFormatter ); +} + + +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() )->GetBox().SetState( static_cast< TriState >( nState ) ); +} + + +bool DbCheckBox::commitControl() +{ + m_rColumn.getModel()->setPropertyValue( FM_PROP_STATE, + makeAny( static_cast( static_cast< CheckBoxControl* >( m_pWindow.get() )->GetBox().GetState() ) ) ); + return true; +} + + +OUString DbCheckBox::GetFormatText(const Reference< XColumn >& /*_rxField*/, const Reference< XNumberFormatter >& /*xFormatter*/, Color** /*ppColor*/) +{ + return OUString(); +} + +DbPatternField::DbPatternField( DbGridColumn& _rColumn, const Reference& _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)); + + static_cast< PatternField* >( m_pWindow.get() )->SetMask( aAsciiEditMask, aLitMask ); + static_cast< PatternField* >( m_pPainter.get() )->SetMask( aAsciiEditMask, aLitMask ); + static_cast< PatternField* >( m_pWindow.get() )->SetStrictFormat( bStrict ); + static_cast< PatternField* >( m_pPainter.get() )->SetStrictFormat( bStrict ); +} + + +void DbPatternField::Init( vcl::Window& rParent, const Reference< XRowSet >& xCursor) +{ + m_rColumn.SetAlignmentFromModel(-1); + + m_pWindow = VclPtr::Create( &rParent, 0 ); + m_pPainter= VclPtr::Create( &rParent, 0 ); + + Reference< XPropertySet > xModel( m_rColumn.getModel() ); + implAdjustGenericFieldSetting( xModel ); + + DbCellControl::Init( rParent, xCursor ); +} + + +CellControllerRef DbPatternField::CreateController() const +{ + return new SpinCellController( static_cast< PatternField* >( m_pWindow.get() ) ); +} + + +OUString DbPatternField::impl_formatText( const OUString& _rText ) +{ + m_pPainter->SetText( _rText ); + static_cast< PatternField* >( m_pPainter.get() )->ReformatAll(); + return m_pPainter->GetText(); +} + + +OUString DbPatternField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, 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 ) +{ + static_cast< Edit* >( m_pWindow.get() )->SetText( GetFormatText( _rxField, _rxFormatter ) ); + static_cast< Edit* >( m_pWindow.get() )->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) ); +} + + +void DbPatternField::updateFromModel( Reference< XPropertySet > _rxModel ) +{ + OSL_ENSURE( _rxModel.is() && m_pWindow, "DbPatternField::updateFromModel: invalid call!" ); + + OUString sText; + _rxModel->getPropertyValue( FM_PROP_TEXT ) >>= sText; + + static_cast< Edit* >( m_pWindow.get() )->SetText( impl_formatText( sText ) ); + static_cast< Edit* >( m_pWindow.get() )->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) ); +} + + +bool DbPatternField::commitControl() +{ + OUString aText(m_pWindow->GetText()); + m_rColumn.getModel()->setPropertyValue(FM_PROP_TEXT, makeAny(aText)); + return true; +} + +DbSpinField::DbSpinField( DbGridColumn& _rColumn, sal_Int16 _nStandardAlign ) + :DbCellControl( _rColumn ) + ,m_nStandardAlign( _nStandardAlign ) +{ +} + + +void DbSpinField::Init( vcl::Window& _rParent, const Reference< XRowSet >& _rxCursor ) +{ + m_rColumn.SetAlignmentFromModel( m_nStandardAlign ); + + Reference< XPropertySet > xModel( m_rColumn.getModel() ); + + // determine the WinBits for the field + WinBits nFieldStyle = 0; + if ( ::comphelper::getBOOL( xModel->getPropertyValue( FM_PROP_SPIN ) ) ) + nFieldStyle = WB_REPEAT | WB_SPIN; + // create the fields + m_pWindow = createField( &_rParent, nFieldStyle, xModel ); + m_pPainter = createField( &_rParent, nFieldStyle, 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 SpinCellController( static_cast< SpinField* >( 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(getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMIN ) )); + sal_Int32 nMax = static_cast(getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMAX ) )); + sal_Int32 nStep = static_cast(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 ) ); + + static_cast< DoubleNumericField* >( m_pWindow.get() )->SetMinValue(nMin); + static_cast< DoubleNumericField* >( m_pWindow.get() )->SetMaxValue(nMax); + static_cast< DoubleNumericField* >( m_pWindow.get() )->SetSpinSize(nStep); + static_cast< DoubleNumericField* >( m_pWindow.get() )->SetStrictFormat(bStrict); + + static_cast< DoubleNumericField* >( m_pPainter.get() )->SetMinValue(nMin); + static_cast< DoubleNumericField* >( m_pPainter.get() )->SetMaxValue(nMax); + static_cast< DoubleNumericField* >( m_pPainter.get() )->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* pImplmentation = comphelper::getUnoTunnelImplementation( xSupplier ); + pFormatterUsed = pImplmentation ? pImplmentation->GetNumberFormatter() : nullptr; + } + if ( nullptr == pFormatterUsed ) + { // the cursor didn't lead to success -> standard + pFormatterUsed = static_cast< DoubleNumericField* >( m_pWindow.get() )->StandardFormatter(); + DBG_ASSERT( pFormatterUsed != nullptr, "DbNumericField::implAdjustGenericFieldSetting: no standard formatter given by the numeric field !" ); + } + static_cast< DoubleNumericField* >( m_pWindow.get() )->SetFormatter( pFormatterUsed ); + static_cast< DoubleNumericField* >( m_pPainter.get() )->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); + + static_cast< DoubleNumericField* >( m_pWindow.get() )->SetFormat( sFormatString, aAppLanguage ); + static_cast< DoubleNumericField* >( m_pPainter.get() )->SetFormat( sFormatString, aAppLanguage ); +} + + +VclPtr DbNumericField::createField( vcl::Window* _pParent, WinBits _nFieldStyle, const Reference< XPropertySet >& /*_rxModel*/ ) +{ + return VclPtr::Create( _pParent, _nFieldStyle ); +} + +namespace +{ + + OUString lcl_setFormattedNumeric_nothrow( DoubleNumericField& _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.SetValue( fValue ); + sValue = _rField.GetText(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } + } + return sValue; + } +} + + +OUString DbNumericField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter, Color** /*ppColor*/) +{ + return lcl_setFormattedNumeric_nothrow(dynamic_cast(*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(*m_pWindow), *this, _rxField, _rxFormatter); +} + + +void DbNumericField::updateFromModel( Reference< XPropertySet > _rxModel ) +{ + OSL_ENSURE( _rxModel.is() && m_pWindow, "DbNumericField::updateFromModel: invalid call!" ); + + double dValue = 0; + if ( _rxModel->getPropertyValue( FM_PROP_VALUE ) >>= dValue ) + static_cast< DoubleNumericField* >( m_pWindow.get() )->SetValue( dValue ); + else + m_pWindow->SetText( OUString() ); +} + + +bool DbNumericField::commitControl() +{ + OUString aText( m_pWindow->GetText()); + Any aVal; + + if (!aText.isEmpty()) // not empty + { + double fValue = static_cast(m_pWindow.get())->GetValue(); + aVal <<= fValue; + } + m_rColumn.getModel()->setPropertyValue(FM_PROP_VALUE, aVal); + return true; +} + +DbCurrencyField::DbCurrencyField(DbGridColumn& _rColumn) + :DbSpinField( _rColumn ) + ,m_nScale( 0 ) +{ + 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; + + m_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 ) ) ); + + //fdo#42747 the min/max/first/last of vcl NumericFormatters needs to be + //multiplied by the no of decimal places. See also + //VclBuilder::mungeAdjustment + int nMul = rtl_math_pow10Exp(1, m_nScale); + nMin *= nMul; + nMax *= nMul; + + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetUseThousandSep( bThousand ); + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetDecimalDigits( m_nScale ); + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetCurrencySymbol( aStr ); + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetFirst( nMin ); + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetLast( nMax ); + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetMin( nMin ); + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetMax( nMax ); + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetSpinSize( nStep ); + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetStrictFormat( bStrict ); + + static_cast< LongCurrencyField* >( m_pPainter.get() )->SetUseThousandSep( bThousand ); + static_cast< LongCurrencyField* >( m_pPainter.get() )->SetDecimalDigits( m_nScale ); + static_cast< LongCurrencyField* >( m_pPainter.get() )->SetCurrencySymbol( aStr ); + static_cast< LongCurrencyField* >( m_pPainter.get() )->SetFirst( nMin ); + static_cast< LongCurrencyField* >( m_pPainter.get() )->SetLast( nMax ); + static_cast< LongCurrencyField* >( m_pPainter.get() )->SetMin( nMin ); + static_cast< LongCurrencyField* >( m_pPainter.get() )->SetMax( nMax ); + static_cast< LongCurrencyField* >( m_pPainter.get() )->SetStrictFormat( bStrict ); +} + + +VclPtr DbCurrencyField::createField( vcl::Window* _pParent, WinBits _nFieldStyle, const Reference< XPropertySet >& /*_rxModel*/ ) +{ + return VclPtr::Create( _pParent, _nFieldStyle ); +} + + +double DbCurrencyField::GetCurrency(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter) const +{ + double fValue = GetValue(_rxField, xFormatter); + if (m_nScale) + { + // SAL_INFO("svx",("double = %.64f ",fValue); + fValue = ::rtl::math::pow10Exp(fValue, m_nScale); + fValue = ::rtl::math::round(fValue); + } + return fValue; +} + +namespace +{ + + OUString lcl_setFormattedCurrency_nothrow( LongCurrencyField& _rField, const DbCurrencyField& _rControl, + const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter ) + { + OUString sValue; + if ( _rxField.is() ) + { + try + { + double fValue = _rControl.GetCurrency( _rxField, _rxFormatter ); + if ( !_rxField->wasNull() ) + { + _rField.SetValue( fValue ); + sValue = _rField.GetText(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } + } + return sValue; + } +} + + +OUString DbCurrencyField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter, Color** /*ppColor*/) +{ + return lcl_setFormattedCurrency_nothrow( dynamic_cast< LongCurrencyField& >( *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< LongCurrencyField& >( *m_pWindow ), *this, _rxField, _rxFormatter ); +} + + +void DbCurrencyField::updateFromModel( Reference< XPropertySet > _rxModel ) +{ + OSL_ENSURE( _rxModel.is() && m_pWindow, "DbCurrencyField::updateFromModel: invalid call!" ); + + double dValue = 0; + if ( _rxModel->getPropertyValue( FM_PROP_VALUE ) >>= dValue ) + { + if ( m_nScale ) + { + dValue = ::rtl::math::pow10Exp( dValue, m_nScale ); + dValue = ::rtl::math::round(dValue); + } + + static_cast< LongCurrencyField* >( m_pWindow.get() )->SetValue( dValue ); + } + else + m_pWindow->SetText( OUString() ); +} + + +bool DbCurrencyField::commitControl() +{ + OUString aText(m_pWindow->GetText()); + Any aVal; + if (!aText.isEmpty()) // not empty + { + double fValue = static_cast(m_pWindow.get())->GetValue(); + if (m_nScale) + { + fValue /= ::rtl::math::pow10Exp(1.0, m_nScale); + } + 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 DbDateField::createField( vcl::Window* _pParent, WinBits _nFieldStyle, 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 ) ); + if ( bDropDown ) + _nFieldStyle |= WB_DROPDOWN; + + VclPtr pField = VclPtr::Create( _pParent, _nFieldStyle ); + + pField->EnableToday(); + pField->EnableNone(); + + return pField; +} + + +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 ) ); + + Any aCentury = _rxModel->getPropertyValue( FM_PROP_DATE_SHOW_CENTURY ); + if ( aCentury.getValueType().getTypeClass() != TypeClass_VOID ) + { + bool bShowDateCentury = getBOOL( aCentury ); + + static_cast( m_pWindow.get() )->SetShowDateCentury( bShowDateCentury ); + static_cast( m_pPainter.get() )->SetShowDateCentury( bShowDateCentury ); + } + + static_cast< DateField* >( m_pWindow.get() )->SetExtDateFormat( static_cast(nFormat) ); + static_cast< DateField* >( m_pWindow.get() )->SetMin( aMin ); + static_cast< DateField* >( m_pWindow.get() )->SetMax( aMax ); + static_cast< DateField* >( m_pWindow.get() )->SetStrictFormat( bStrict ); + static_cast< DateField* >( m_pWindow.get() )->EnableEmptyFieldValue( true ); + + static_cast< DateField* >( m_pPainter.get() )->SetExtDateFormat( static_cast(nFormat) ); + static_cast< DateField* >( m_pPainter.get() )->SetMin( aMin ); + static_cast< DateField* >( m_pPainter.get() )->SetMax( aMax ); + static_cast< DateField* >( m_pPainter.get() )->SetStrictFormat( bStrict ); + static_cast< DateField* >( m_pPainter.get() )->EnableEmptyFieldValue( true ); +} + +namespace +{ + + OUString lcl_setFormattedDate_nothrow( DateField& _rField, const Reference< XColumn >& _rxField ) + { + OUString sDate; + if ( _rxField.is() ) + { + try + { + css::util::Date aValue = _rxField->getDate(); + if ( _rxField->wasNull() ) + _rField.SetText( sDate ); + else + { + _rField.SetDate( ::Date( aValue.Day, aValue.Month, aValue.Year ) ); + sDate = _rField.GetText(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } + } + return sDate; + } +} + +OUString DbDateField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& /*xFormatter*/, Color** /*ppColor*/) +{ + return lcl_setFormattedDate_nothrow(dynamic_cast(*m_pPainter), _rxField); +} + + +void DbDateField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/) +{ + lcl_setFormattedDate_nothrow(dynamic_cast(*m_pWindow), _rxField); +} + + +void DbDateField::updateFromModel( Reference< XPropertySet > _rxModel ) +{ + OSL_ENSURE( _rxModel.is() && m_pWindow, "DbDateField::updateFromModel: invalid call!" ); + + util::Date aDate; + if ( _rxModel->getPropertyValue( FM_PROP_DATE ) >>= aDate ) + static_cast< DateField* >( m_pWindow.get() )->SetDate( ::Date( aDate ) ); + else + static_cast< DateField* >( m_pWindow.get() )->SetText( OUString() ); +} + + +bool DbDateField::commitControl() +{ + OUString aText(m_pWindow->GetText()); + Any aVal; + if (!aText.isEmpty()) + aVal <<= static_cast(m_pWindow.get())->GetDate().GetUNODate(); + else + aVal.clear(); + + 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 DbTimeField::createField( vcl::Window* _pParent, WinBits _nFieldStyle, const Reference< XPropertySet >& /*_rxModel*/ ) +{ + return VclPtr::Create( _pParent, _nFieldStyle ); +} + + +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 ) ); + + static_cast< TimeField* >( m_pWindow.get() )->SetExtFormat( static_cast(nFormat) ); + static_cast< TimeField* >( m_pWindow.get() )->SetMin( aMin ); + static_cast< TimeField* >( m_pWindow.get() )->SetMax( aMax ); + static_cast< TimeField* >( m_pWindow.get() )->SetStrictFormat( bStrict ); + static_cast< TimeField* >( m_pWindow.get() )->EnableEmptyFieldValue( true ); + + static_cast< TimeField* >( m_pPainter.get() )->SetExtFormat( static_cast(nFormat) ); + static_cast< TimeField* >( m_pPainter.get() )->SetMin( aMin ); + static_cast< TimeField* >( m_pPainter.get() )->SetMax( aMax ); + static_cast< TimeField* >( m_pPainter.get() )->SetStrictFormat( bStrict ); + static_cast< TimeField* >( m_pPainter.get() )->EnableEmptyFieldValue( true ); +} + +namespace +{ + + OUString lcl_setFormattedTime_nothrow( TimeField& _rField, const Reference< XColumn >& _rxField ) + { + OUString sTime; + if ( _rxField.is() ) + { + try + { + css::util::Time aValue = _rxField->getTime(); + if ( _rxField->wasNull() ) + _rField.SetText( sTime ); + else + { + _rField.SetTime( ::tools::Time( aValue ) ); + sTime = _rField.GetText(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } + } + return sTime; + } +} + +OUString DbTimeField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& /*xFormatter*/, Color** /*ppColor*/) +{ + return lcl_setFormattedTime_nothrow( *static_cast< TimeField* >( m_pPainter.get() ), _rxField ); +} + + +void DbTimeField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/) +{ + lcl_setFormattedTime_nothrow( *static_cast< TimeField* >( m_pWindow.get() ), _rxField ); +} + + +void DbTimeField::updateFromModel( Reference< XPropertySet > _rxModel ) +{ + OSL_ENSURE( _rxModel.is() && m_pWindow, "DbTimeField::updateFromModel: invalid call!" ); + + util::Time aTime; + if ( _rxModel->getPropertyValue( FM_PROP_TIME ) >>= aTime ) + static_cast< TimeField* >( m_pWindow.get() )->SetTime( ::tools::Time( aTime ) ); + else + static_cast< TimeField* >( m_pWindow.get() )->SetText( OUString() ); +} + + +bool DbTimeField::commitControl() +{ + OUString aText(m_pWindow->GetText()); + Any aVal; + if (!aText.isEmpty()) + aVal <<= static_cast(m_pWindow.get())->GetTime().GetUNOTime(); + else + aVal.clear(); + + 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(m_pWindow.get()); + weld::ComboBox& rComboBox = pField->get_widget(); + rComboBox.clear(); + + css::uno::Sequence 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&) +{ + // we no longer pay attention to FM_PROP_LINECOUNT +} + +void DbComboBox::Init( vcl::Window& rParent, const Reference< XRowSet >& xCursor ) +{ + m_rColumn.SetAlignmentFromModel(css::awt::TextAlign::LEFT); + + m_pWindow = VclPtr::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(m_pWindow.get())); +} + + +OUString DbComboBox::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter, Color** /*ppColor*/) +{ + const css::uno::Reference 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(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(m_pWindow.get()); + weld::ComboBox& rComboBox = pControl->get_widget(); + rComboBox.set_entry_text(sText); + rComboBox.select_entry_region(0, -1); +} + +bool DbComboBox::commitControl() +{ + ComboBoxControl* pControl = static_cast(m_pWindow.get()); + weld::ComboBox& rComboBox = pControl->get_widget(); + OUString aText(rComboBox.get_active_text()); + m_rColumn.getModel()->setPropertyValue(FM_PROP_TEXT, makeAny(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(m_pWindow.get()); + + weld::ComboBox& rFieldList = pField->get_widget(); + + rFieldList.clear(); + m_bBound = false; + + css::uno::Sequence aTest; + if (rItems >>= aTest) + { + 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( vcl::Window& rParent, const Reference< XRowSet >& xCursor) +{ + m_rColumn.SetAlignment(css::awt::TextAlign::LEFT); + + m_pWindow = VclPtr::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(m_pWindow.get())); +} + +OUString DbListBox::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, 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(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(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 ]; + + weld::ComboBox& rComboBox = static_cast(m_pWindow.get())->get_widget(); + + if (nSelection >= 0 && nSelection < rComboBox.get_count()) + rComboBox.set_active(nSelection); + else + rComboBox.set_active(-1); +} + +bool DbListBox::commitControl() +{ + Any aVal; + Sequence aSelectSeq; + weld::ComboBox& rComboBox = static_cast(m_pWindow.get())->get_widget(); + auto nActive = rComboBox.get_active(); + if (nActive != -1) + { + aSelectSeq.realloc(1); + *aSelectSeq.getArray() = static_cast(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(m_pWindow.get())->SetClickHdl( Link,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: + DbCellControl::PaintCell( rDev, rRect ); + break; + case FormComponentType::LISTBOX: + rDev.DrawText(rRect, static_cast(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 aTest; + rItems >>= aTest; + if (aTest.hasElements()) + { + if (bComboBox) + { + ComboBoxControl* pField = static_cast(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(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(vcl::Window* pParent, const Reference< css::beans::XPropertySet >& xModel) +{ + switch (m_nControlClass) + { + case css::form::FormComponentType::CHECKBOX: + m_pWindow = VclPtr::Create(pParent); + m_pWindow->SetPaintTransparent( true ); + static_cast(m_pWindow.get())->SetClickHdl( LINK( this, DbFilterField, OnClick ) ); + + m_pPainter = VclPtr::Create(pParent); + m_pPainter->SetPaintTransparent( true ); + m_pPainter->SetBackground(); + break; + case css::form::FormComponentType::LISTBOX: + { + m_pWindow = VclPtr::Create(pParent); + Any aItems = xModel->getPropertyValue(FM_PROP_STRINGITEMLIST); + SetList(aItems, false); + } break; + case css::form::FormComponentType::COMBOBOX: + { + m_pWindow = VclPtr::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::Create(pParent, WB_LEFT); + 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( vcl::Window& 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 + Edit* pAsEdit = dynamic_cast< Edit* >( m_pWindow.get() ); + if ( pAsEdit ) + pAsEdit->SetReadOnly( false ); +} + +CellControllerRef DbFilterField::CreateController() const +{ + CellControllerRef xController; + switch (m_nControlClass) + { + case css::form::FormComponentType::CHECKBOX: + xController = new CheckBoxCellController(static_cast(m_pWindow.get())); + break; + case css::form::FormComponentType::LISTBOX: + xController = new ListBoxCellController(static_cast(m_pWindow.get())); + break; + case css::form::FormComponentType::COMBOBOX: + xController = new ComboBoxCellController(static_cast(m_pWindow.get())); + break; + default: + if (m_bFilterList) + xController = new ComboBoxCellController(static_cast(m_pWindow.get())); + else + xController = new EditCellController(static_cast(m_pWindow.get())); + } + return xController; +} + +void DbFilterField::updateFromModel( Reference< XPropertySet > _rxModel ) +{ + OSL_ENSURE( _rxModel.is() && m_pWindow, "DbFilterField::updateFromModel: invalid call!" ); + + OSL_FAIL( "DbListBox::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(m_pWindow.get())->get_widget(); + auto nActive = rComboBox.get_active(); + if (nActive != -1) + { + sal_Int16 nPos = static_cast(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; + } + default: + aText = m_pWindow->GetText(); + } + + 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, 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(m_pWindow.get())->GetBox().SetState(eState); + static_cast(m_pPainter.get())->GetBox().SetState(eState); + } break; + case css::form::FormComponentType::LISTBOX: + { + sal_Int32 nPos = ::comphelper::findValue(m_aValueList, m_aText); + static_cast(m_pWindow.get())->get_widget().set_active(nPos); + } break; + default: + m_pWindow->SetText(m_aText); + } + + // 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 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, makeAny(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(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*/, 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, OnClick, VclPtr, void) +{ + TriState eState = static_cast(m_pWindow.get())->GetBox().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("", true, nBooleanComparisonMode, aTextBuf); + break; + case TRISTATE_FALSE: + ::dbtools::getBooleanComparisonPredicate("", 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 _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() +{ + vcl::Window* pEventWindow( getEventWindow() ); + if ( pEventWindow ) + pEventWindow->AddEventListener( LINK( this, FmXGridCell, OnWindowEvent ) ); +} + + +vcl::Window* 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" ); +} + + +IMPL_LINK( FmXGridCell, OnWindowEvent, VclWindowEvent&, _rEvent, void ) +{ + ENSURE_OR_THROW( _rEvent.GetWindow(), "illegal window" ); + onWindowEvent( _rEvent.GetId(), *_rEvent.GetWindow(), _rEvent.GetData() ); +} + + +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 ); +} + + +void FmXGridCell::onWindowEvent( const VclEventId _nEventId, const vcl::Window& _rWindow, const void* _pEventData ) +{ + switch ( _nEventId ) + { + case VclEventId::ControlGetFocus: + case VclEventId::WindowGetFocus: + case VclEventId::ControlLoseFocus: + case VclEventId::WindowLoseFocus: + { + if ( ( _rWindow.IsCompoundControl() + && ( _nEventId == VclEventId::ControlGetFocus + || _nEventId == VclEventId::ControlLoseFocus + ) + ) + || ( !_rWindow.IsCompoundControl() + && ( _nEventId == VclEventId::WindowGetFocus + || _nEventId == VclEventId::WindowLoseFocus + ) + ) + ) + { + if ( !m_aFocusListeners.getLength() ) + break; + + bool bFocusGained = ( _nEventId == VclEventId::ControlGetFocus ) || ( _nEventId == VclEventId::WindowGetFocus ); + + awt::FocusEvent aEvent; + aEvent.Source = *this; + aEvent.FocusFlags = static_cast(_rWindow.GetGetFocusFlags()); + aEvent.Temporary = false; + + if ( bFocusGained ) + onFocusGained( aEvent ); + else + onFocusLost( aEvent ); + } + } + break; + case VclEventId::WindowMouseButtonDown: + case VclEventId::WindowMouseButtonUp: + { + if ( !m_aMouseListeners.getLength() ) + break; + + const bool bButtonDown = ( _nEventId == VclEventId::WindowMouseButtonDown ); + + awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( *static_cast< const ::MouseEvent* >( _pEventData ), *this ) ); + m_aMouseListeners.notifyEach( bButtonDown ? &awt::XMouseListener::mousePressed : &awt::XMouseListener::mouseReleased, aEvent ); + } + break; + case VclEventId::WindowMouseMove: + { + const MouseEvent& rMouseEvent = *static_cast< const ::MouseEvent* >( _pEventData ); + 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 ); + } + } + } + break; + case VclEventId::WindowKeyInput: + case VclEventId::WindowKeyUp: + { + if ( !m_aKeyListeners.getLength() ) + break; + + const bool bKeyPressed = ( _nEventId == VclEventId::WindowKeyInput ); + awt::KeyEvent aEvent( VCLUnoHelper::createKeyEvent( *static_cast< const ::KeyEvent* >( _pEventData ), *this ) ); + m_aKeyListeners.notifyEach( bKeyPressed ? &awt::XKeyListener::keyPressed: &awt::XKeyListener::keyReleased, aEvent ); + } + break; + default: break; + } +} + + +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 pControl ) + :FmXDataCell( pColumn, std::move(pControl) ) + ,m_bFastPaint( true ) +{ +} + + +void FmXTextCell::PaintFieldToCell(OutputDevice& rDev, + const tools::Rectangle& rRect, + const Reference< css::sdb::XColumn >& _rxField, + const Reference< XNumberFormatter >& xFormatter) +{ + if ( !m_bFastPaint ) + { + FmXDataCell::PaintFieldToCell( rDev, rRect, _rxField, xFormatter ); + return; + } + + DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::VCenter; + if ( ( rDev.GetOutDevType() == OUTDEV_WINDOW ) && !static_cast< vcl::Window& >( rDev ).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; + } + + try + { + 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 pControl ) + :FmXTextCell( pColumn, std::move(pControl) ) + ,m_aTextListeners(m_aMutex) + ,m_aChangeListeners( m_aMutex ) + ,m_pEditImplementation( nullptr ) + ,m_bOwnEditImplementation( false ) +{ + + DbTextField* pTextField = dynamic_cast( m_pCellControl.get() ); + if ( pTextField ) + { + + m_pEditImplementation = pTextField->GetEditImplementation(); + if ( !pTextField->IsSimpleEdit() ) + m_bFastPaint = false; + } + else + { + m_pEditImplementation = new EditImplementation( static_cast< Edit& >( m_pCellControl->GetWindow() ) ); + m_bOwnEditImplementation = true; + } +} + + +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); + + m_pEditImplementation->SetModifyHdl( Link() ); + 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 ); + } +} + + +void FmXEditCell::onWindowEvent( const VclEventId _nEventId, const vcl::Window& _rWindow, const void* _pEventData ) +{ + switch ( _nEventId ) + { + case VclEventId::EditModify: + { + if ( m_pEditImplementation && m_aTextListeners.getLength() ) + onTextChanged(); + return; + } + default: break; + } + + FmXTextCell::onWindowEvent( _nEventId, _rWindow, _pEventData ); +} + +FmXCheckBoxCell::FmXCheckBoxCell( DbGridColumn* pColumn, std::unique_ptr pControl ) + :FmXDataCell( pColumn, std::move(pControl) ) + ,m_aItemListeners(m_aMutex) + ,m_aActionListeners( m_aMutex ) + ,m_pBox( & static_cast< CheckBoxControl& >( m_pCellControl->GetWindow() ).GetBox() ) +{ +} + + +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); + + static_cast< CheckBoxControl& >( m_pCellControl->GetWindow() ).SetClickHdl(Link,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(n) ); + } +} + + +sal_Int16 SAL_CALL FmXCheckBoxCell::getState() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if (m_pBox) + { + UpdateFromColumn(); + return static_cast(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; +} + + +vcl::Window* FmXCheckBoxCell::getEventWindow() const +{ + return m_pBox; +} + + +void FmXCheckBoxCell::onWindowEvent( const VclEventId _nEventId, const vcl::Window& _rWindow, const void* _pEventData ) +{ + switch ( _nEventId ) + { + case VclEventId::CheckboxToggle: + { + // 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 ); + } + } + break; + + default: + FmXDataCell::onWindowEvent( _nEventId, _rWindow, _pEventData ); + break; + } +} + +FmXListBoxCell::FmXListBoxCell(DbGridColumn* pColumn, std::unique_ptr pControl) + : FmXTextCell(pColumn, std::move(pControl)) + , m_aItemListeners(m_aMutex) + , m_aActionListeners(m_aMutex) + , m_pBox(&static_cast(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()); + 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& 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 SAL_CALL FmXListBoxCell::getItems() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + css::uno::Sequence aSeq; + if (m_pBox) + { + weld::ComboBox& rBox = m_pBox->get_widget(); + const sal_Int32 nEntries = rBox.get_count(); + aSeq = css::uno::Sequence( 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 ); + Sequence aSeq; + + if (m_pBox) + { + UpdateFromColumn(); + weld::ComboBox& rBox = m_pBox->get_widget(); + auto nActive = rBox.get_active(); + if (nActive != -1) + { + aSeq = Sequence(1); + aSeq.getArray()[0] = nActive; + } + } + return aSeq; +} + +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 SAL_CALL FmXListBoxCell::getSelectedItems() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + css::uno::Sequence aSeq; + + if (m_pBox) + { + UpdateFromColumn(); + weld::ComboBox& rBox = m_pBox->get_widget(); + auto nActive = rBox.get_active(); + if (nActive != -1) + { + aSeq = css::uno::Sequence(1); + aSeq.getArray()[0] = rBox.get_text(nActive); + } + } + return aSeq; +} + +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(aPositions.getLength()); n; ) + { + auto nPos = static_cast(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_NOARG(FmXListBoxCell, ChangedHdl, LinkParamNone*, void) +{ + if (!m_pBox) + return; + + weld::ComboBox& rBox = m_pBox->get_widget(); + + if (!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() +{ + ::comphelper::OInterfaceIteratorHelper2 aIt( m_aActionListeners ); + + css::awt::ActionEvent aEvent; + aEvent.Source = *this; + weld::ComboBox& rBox = m_pBox->get_widget(); + aEvent.ActionCommand = rBox.get_active_text(); + + while( aIt.hasMoreElements() ) + static_cast< css::awt::XActionListener *>(aIt.next())->actionPerformed( aEvent ); +} + +FmXComboBoxCell::FmXComboBoxCell( DbGridColumn* pColumn, std::unique_ptr pControl ) + :FmXTextCell( pColumn, std::move(pControl) ) + ,m_aItemListeners( m_aMutex ) + ,m_aActionListeners( m_aMutex ) + ,m_pComboBox(&static_cast(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()); + 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; nget_widget(); + + if (!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 pControl ) + :FmXGridCell( pColumn, std::move(pControl) ) + ,m_aTextListeners(m_aMutex) +{ + static_cast(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 ) +{ + sal_Int64 nReturn(0); + + if ( isUnoTunnelId(_rIdentifier) ) + { + nReturn = reinterpret_cast(this); + } + + return nReturn; +} + +namespace +{ + class theFmXFilterCellUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theFmXFilterCellUnoTunnelId > {}; +} + +const Sequence& FmXFilterCell::getUnoTunnelId() +{ + return theFmXFilterCellUnoTunnelId::get().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(m_pCellControl.get())->SetCommitHdl(Link()); + + 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(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(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) +{ + ::comphelper::OInterfaceIteratorHelper2 aIt( m_aTextListeners ); + css::awt::TextEvent aEvt; + aEvt.Source = *this; + while( aIt.hasMoreElements() ) + static_cast< css::awt::XTextListener *>(aIt.next())->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..1e44ece89 --- /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 +#include +#include +#include + +using namespace ::com::sun::star::uno; + + +static const css::uno::Sequence& getColumnTypes() +{ + static css::uno::Sequence aColumnTypes = [&]() + { + css::uno::Sequence 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(pFirst)->compareTo(*static_cast(pSecond)); +} + +} + +namespace +{ + + sal_Int32 lcl_findPos(const OUString& aStr, const Sequence< OUString>& rList) + { + const OUString* pStrList = rList.getConstArray(); + OUString* pResult = static_cast(bsearch(&aStr, static_cast(pStrList), rList.getLength(), sizeof(OUString), + &NameCompare)); + + if (pResult) + return (pResult - pStrList); + else + return -1; + } +} + + +sal_Int32 getColumnTypeByModelName(const OUString& aModelName) +{ + const OUString aModelPrefix("com.sun.star.form.component."); + const OUString aCompatibleModelPrefix("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& 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..4c9795bad --- /dev/null +++ b/svx/source/fmcomp/gridctrl.cxx @@ -0,0 +1,3645 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +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") + +static 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 +{ + VclPtr 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 ) + { + ::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 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.get() == nullptr, "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 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(); + } +} + +static 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 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); +} + +DbGridControl::NavigationBar::AbsolutePos::AbsolutePos(vcl::Window* pParent, WinBits nStyle) + :NumericField(pParent, nStyle) +{ + SetMin(1); + SetFirst(1); + SetSpinSize(1); + + SetDecimalDigits(0); + SetStrictFormat(true); +} + +void DbGridControl::NavigationBar::AbsolutePos::KeyInput(const KeyEvent& rEvt) +{ + if (rEvt.GetKeyCode() == KEY_RETURN && !GetText().isEmpty()) + { + sal_Int64 nRecord = GetValue(); + if (nRecord < GetMin() || nRecord > GetMax()) + return; + else + static_cast(GetParent())->PositionDataSource(static_cast(nRecord)); + } + else if (rEvt.GetKeyCode() == KEY_TAB) + GetParent()->GetParent()->GrabFocus(); + else + NumericField::KeyInput(rEvt); +} + +void DbGridControl::NavigationBar::AbsolutePos::LoseFocus() +{ + NumericField::LoseFocus(); + sal_Int64 nRecord = GetValue(); + if (nRecord < GetMin() || nRecord > GetMax()) + return; + else + { + static_cast(GetParent())->PositionDataSource(static_cast(nRecord)); + static_cast(GetParent())->InvalidateState(DbGridControlNavigationBarState::Absolute); + } +} + +void DbGridControl::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(GetParent())->MoveToPosition(nRecord - 1); + m_bPositioning = false; +} + +DbGridControl::NavigationBar::NavigationBar(vcl::Window* pParent) + :Control(pParent, 0) + ,m_aRecordText(VclPtr::Create(this, WB_VCENTER)) + ,m_aAbsolute(VclPtr::Create(this, WB_CENTER | WB_VCENTER)) + ,m_aRecordOf(VclPtr::Create(this, WB_VCENTER)) + ,m_aRecordCount(VclPtr::Create(this, WB_VCENTER)) + ,m_aFirstBtn(VclPtr::Create(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)) + ,m_aPrevBtn(VclPtr::Create(this, WB_REPEAT|WB_RECTSTYLE|WB_NOPOINTERFOCUS)) + ,m_aNextBtn(VclPtr::Create(this, WB_REPEAT|WB_RECTSTYLE|WB_NOPOINTERFOCUS)) + ,m_aLastBtn(VclPtr::Create(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)) + ,m_aNewBtn(VclPtr::Create(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)) + ,m_nCurrentPos(-1) + ,m_bPositioning(false) +{ + m_aFirstBtn->SetSymbol(SymbolType::FIRST); + m_aPrevBtn->SetSymbol(SymbolType::PREV); + m_aNextBtn->SetSymbol(SymbolType::NEXT); + m_aLastBtn->SetSymbol(SymbolType::LAST); + m_aNewBtn->SetModeImage(static_cast(pParent)->GetImage(EditBrowseBox::NEW)); + + m_aFirstBtn->SetHelpId(HID_GRID_TRAVEL_FIRST); + m_aPrevBtn->SetHelpId(HID_GRID_TRAVEL_PREV); + m_aNextBtn->SetHelpId(HID_GRID_TRAVEL_NEXT); + m_aLastBtn->SetHelpId(HID_GRID_TRAVEL_LAST); + m_aNewBtn->SetHelpId(HID_GRID_TRAVEL_NEW); + m_aAbsolute->SetHelpId(HID_GRID_TRAVEL_ABSOLUTE); + m_aRecordCount->SetHelpId(HID_GRID_NUMBEROFRECORDS); + + // set handlers for buttons + m_aFirstBtn->SetClickHdl(LINK(this,NavigationBar,OnClick)); + m_aPrevBtn->SetClickHdl(LINK(this,NavigationBar,OnClick)); + m_aNextBtn->SetClickHdl(LINK(this,NavigationBar,OnClick)); + m_aLastBtn->SetClickHdl(LINK(this,NavigationBar,OnClick)); + m_aNewBtn->SetClickHdl(LINK(this,NavigationBar,OnClick)); + + m_aRecordText->SetText(SvxResId(RID_STR_REC_TEXT)); + m_aRecordOf->SetText(SvxResId(RID_STR_REC_FROM_TEXT)); + m_aRecordCount->SetText(OUString('?')); + + m_aFirstBtn->Disable(); + m_aPrevBtn->Disable(); + m_aNextBtn->Disable(); + m_aLastBtn->Disable(); + m_aNewBtn->Disable(); + m_aRecordText->Disable(); + m_aRecordOf->Disable(); + m_aRecordCount->Disable(); + m_aAbsolute->Disable(); + + AllSettings aSettings = m_aNextBtn->GetSettings(); + MouseSettings aMouseSettings = aSettings.GetMouseSettings(); + aMouseSettings.SetButtonRepeat(aMouseSettings.GetButtonRepeat() / 4); + aSettings.SetMouseSettings(aMouseSettings); + m_aNextBtn->SetSettings(aSettings, true); + m_aPrevBtn->SetSettings(aSettings, true); + + m_aFirstBtn->Show(); + m_aPrevBtn->Show(); + m_aNextBtn->Show(); + m_aLastBtn->Show(); + m_aNewBtn->Show(); + m_aRecordText->Show(); + m_aRecordOf->Show(); + m_aRecordCount->Show(); + m_aAbsolute->Show(); +} + + +DbGridControl::NavigationBar::~NavigationBar() +{ + disposeOnce(); +} + +void DbGridControl::NavigationBar::dispose() +{ + m_aRecordText.disposeAndClear(); + m_aAbsolute.disposeAndClear(); + m_aRecordOf.disposeAndClear(); + m_aRecordCount.disposeAndClear(); + m_aFirstBtn.disposeAndClear(); + m_aPrevBtn.disposeAndClear(); + m_aNextBtn.disposeAndClear(); + m_aLastBtn.disposeAndClear(); + m_aNewBtn.disposeAndClear(); + Control::dispose(); +} + +namespace +{ + void SetPosAndSize(Button& _rButton,Point& _rPos,const Size& _rSize) + { + _rButton.SetPosPixel( _rPos ); + _rButton.SetSizePixel( _rSize ); + _rPos.AdjustX(static_cast(_rSize.Width()) ); + } +} + +sal_uInt16 DbGridControl::NavigationBar::ArrangeControls() +{ + // positioning of the controls + // calculate base size + tools::Rectangle aRect(static_cast(GetParent())->GetControlArea()); + long nH = aRect.GetSize().Height(); + long nW = GetParent()->GetOutputSizePixel().Width(); + Size aBorder = LogicToPixel(Size(2, 2), MapMode(MapUnit::MapAppFont)); + aBorder = Size(CalcZoom(aBorder.Width()), CalcZoom(aBorder.Height())); + sal_uInt16 nX = 1; + sal_uInt16 nY = 0; + + { + vcl::Font aApplFont(GetSettings().GetStyleSettings().GetToolFont()); + m_aAbsolute->SetControlFont( aApplFont ); + aApplFont.SetTransparent( true ); + m_aRecordText->SetControlFont( aApplFont ); + m_aRecordOf->SetControlFont( aApplFont ); + m_aRecordCount->SetControlFont( aApplFont ); + } + + // set size and position of the control + OUString aText = m_aRecordText->GetText(); + long nTextWidth = m_aRecordText->GetTextWidth(aText); + m_aRecordText->SetPosPixel(Point(nX,nY)); + m_aRecordText->SetSizePixel(Size(nTextWidth,nH)); + nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width()); + + // count an extra hairspace (U+200A) left and right + const OUString sevenDigits(m_aAbsolute->CreateFieldText(6000000)); + const OUString hairSpace(u'\x200A'); + OUString textPattern = hairSpace + sevenDigits + hairSpace; + nTextWidth = m_aAbsolute->GetTextWidth(textPattern); + m_aAbsolute->SetPosPixel(Point(nX,nY)); + m_aAbsolute->SetSizePixel(Size(nTextWidth, nH)); + nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width()); + + aText = m_aRecordOf->GetText(); + nTextWidth = m_aRecordOf->GetTextWidth(aText); + m_aRecordOf->SetPosPixel(Point(nX,nY)); + m_aRecordOf->SetSizePixel(Size(nTextWidth,nH)); + nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width()); + + textPattern = sevenDigits + " * (" + sevenDigits + ")"; + nTextWidth = m_aRecordCount->GetTextWidth(textPattern); + m_aRecordCount->SetPosPixel(Point(nX,nY)); + m_aRecordCount->SetSizePixel(Size(nTextWidth,nH)); + nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width()); + + Point aButtonPos(nX,nY); + const Size aButtonSize(nH,nH); + SetPosAndSize(*m_aFirstBtn, aButtonPos, aButtonSize); + SetPosAndSize(*m_aPrevBtn, aButtonPos, aButtonSize); + SetPosAndSize(*m_aNextBtn, aButtonPos, aButtonSize); + SetPosAndSize(*m_aLastBtn, aButtonPos, aButtonSize); + SetPosAndSize(*m_aNewBtn, aButtonPos, aButtonSize); + + nX = sal::static_int_cast< sal_uInt16 >(aButtonPos.X() + 1); + + nW = std::max(nW - GetSettings().GetStyleSettings().GetScrollBarSize(), 0L); + + if (nX > nW) + { + aButtonPos.setX( nW-nH ); + m_aNewBtn->SetPosPixel(aButtonPos); + aButtonPos.AdjustX( -nH ); + m_aLastBtn->SetPosPixel(aButtonPos); + aButtonPos.AdjustX( -nH ); + m_aNextBtn->SetPosPixel(aButtonPos); + aButtonPos.AdjustX( -nH ); + m_aPrevBtn->SetPosPixel(aButtonPos); + aButtonPos.AdjustX( -nH ); + m_aFirstBtn->SetPosPixel(aButtonPos); + + auto nDiff = nX - nW; + + Size aSize = m_aAbsolute->GetSizePixel(); + aSize.AdjustWidth( -(nDiff/3.0) ); + m_aAbsolute->SetSizePixel(aSize); + + aSize = m_aRecordCount->GetSizePixel(); + aSize.AdjustWidth( -(nDiff/3.0*2) ); + m_aRecordCount->SetSizePixel(aSize); + + Point aPos = m_aRecordOf->GetPosPixel(); + aPos.AdjustX( -(nDiff/3.0) ); + m_aRecordOf->SetPosPixel(aPos); + + aPos = m_aRecordCount->GetPosPixel(); + aPos.AdjustX( -(nDiff/3.0) ); + m_aRecordCount->SetPosPixel(aPos); + + vcl::Window* pWindows[] = + { + m_aRecordText.get(), + m_aAbsolute.get(), + m_aRecordOf.get(), + m_aRecordCount.get(), + m_aFirstBtn.get(), + m_aPrevBtn.get(), + m_aNextBtn.get(), + m_aLastBtn.get(), + m_aNewBtn.get() + }; + + for (vcl::Window* pWindow : pWindows) + { + if (pWindow->GetPosPixel().X() < 0) + pWindow->SetSizePixel(Size(0, nH)); + aSize = pWindow->GetSizePixel(); + auto nExcess = (pWindow->GetPosPixel().X() + aSize.Width()) - nW; + if (nExcess > 0) + { + aSize.AdjustWidth( -nExcess ); + pWindow->SetSizePixel(aSize); + } + } + + nX = nW; + } + + return nX; +} + +IMPL_LINK(DbGridControl::NavigationBar, OnClick, Button *, pButton, void ) +{ + DbGridControl* pParent = static_cast(GetParent()); + + if (pParent->m_aMasterSlotExecutor.IsSet()) + { + bool lResult = false; + if (pButton == m_aFirstBtn.get()) + lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::First); + else if( pButton == m_aPrevBtn.get() ) + lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::Prev); + else if( pButton == m_aNextBtn.get() ) + lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::Next); + else if( pButton == m_aLastBtn.get() ) + lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::Last); + else if( pButton == m_aNewBtn.get() ) + lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::New); + + if (lResult) + // the link already handled it + return; + } + + if (pButton == m_aFirstBtn.get()) + pParent->MoveToFirst(); + else if( pButton == m_aPrevBtn.get() ) + pParent->MoveToPrev(); + else if( pButton == m_aNextBtn.get() ) + pParent->MoveToNext(); + else if( pButton == m_aLastBtn.get() ) + pParent->MoveToLast(); + else if( pButton == m_aNewBtn.get() ) + pParent->AppendNew(); +} + +void DbGridControl::NavigationBar::InvalidateAll(sal_Int32 nCurrentPos, bool bAll) +{ + if (m_nCurrentPos != nCurrentPos || nCurrentPos < 0 || bAll) + { + DbGridControl* pParent = static_cast(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 DbGridControl::NavigationBar::GetState(DbGridControlNavigationBarState nWhich) const +{ + DbGridControl* pParent = static_cast(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()) + { + 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 DbGridControl::NavigationBar::SetState(DbGridControlNavigationBarState nWhich) +{ + bool bAvailable = GetState(nWhich); + DbGridControl* pParent = static_cast(GetParent()); + vcl::Window* pWnd = nullptr; + switch (nWhich) + { + case DbGridControlNavigationBarState::First: + pWnd = m_aFirstBtn.get(); + break; + case DbGridControlNavigationBarState::Prev: + pWnd = m_aPrevBtn.get(); + break; + case DbGridControlNavigationBarState::Next: + pWnd = m_aNextBtn.get(); + break; + case DbGridControlNavigationBarState::Last: + pWnd = m_aLastBtn.get(); + break; + case DbGridControlNavigationBarState::New: + pWnd = m_aNewBtn.get(); + break; + case DbGridControlNavigationBarState::Absolute: + pWnd = m_aAbsolute.get(); + if (bAvailable) + { + if (pParent->m_nTotalCount >= 0) + { + if (pParent->IsCurrentAppending()) + m_aAbsolute->SetMax(pParent->m_nTotalCount + 1); + else + m_aAbsolute->SetMax(pParent->m_nTotalCount); + } + else + m_aAbsolute->SetMax(LONG_MAX); + + m_aAbsolute->SetValue(m_nCurrentPos + 1); + } + else + m_aAbsolute->SetText(OUString()); + break; + case DbGridControlNavigationBarState::Text: + pWnd = m_aRecordText.get(); + break; + case DbGridControlNavigationBarState::Of: + pWnd = m_aRecordOf.get(); + break; + case DbGridControlNavigationBarState::Count: + { + pWnd = m_aRecordCount.get(); + OUString aText; + if (bAvailable) + { + if (pParent->GetOptions() & DbGridControlOptions::Insert) + { + if (pParent->IsCurrentAppending() && !pParent->IsModified()) + aText = m_aAbsolute->CreateFieldText(pParent->GetRowCount()); + else + aText = m_aAbsolute->CreateFieldText(pParent->GetRowCount() - 1); + } + else + aText = m_aAbsolute->CreateFieldText(pParent->GetRowCount()); + if(!pParent->m_bRecordCountFinal) + aText += " *"; + } + else + aText.clear(); + + // add the number of selected rows, if applicable + if (pParent->GetSelectRowCount()) + { + OUString aExtendedInfo = aText + " (" + + m_aAbsolute->CreateFieldText(pParent->GetSelectRowCount()) + ")"; + pWnd->SetText(aExtendedInfo); + } + else + pWnd->SetText(aText); + + pParent->SetRealRowCount(aText); + } break; + default: break; + } + DBG_ASSERT(pWnd, "no window"); + if (pWnd && (pWnd->IsEnabled() != bAvailable)) + // 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->Enable(bAvailable); +} + +void DbGridControl::NavigationBar::Resize() +{ + Control::Resize(); + ArrangeControls(); +} + +void DbGridControl::NavigationBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + Control::Paint(rRenderContext, rRect); + Point aAbsolutePos = m_aAbsolute->GetPosPixel(); + Size aAbsoluteSize = m_aAbsolute->GetSizePixel(); + + rRenderContext.DrawLine(Point(aAbsolutePos.X() - 1, 0 ), + Point(aAbsolutePos.X() - 1, aAbsolutePos.Y() + aAbsoluteSize.Height())); + + rRenderContext.DrawLine(Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, 0 ), + Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, aAbsolutePos.Y() + aAbsoluteSize.Height())); +} + +void DbGridControl::NavigationBar::StateChanged(StateChangedType nType) +{ + Control::StateChanged(nType); + + vcl::Window* pWindows[] = + { + m_aRecordText.get(), + m_aAbsolute.get(), + m_aRecordOf.get(), + m_aRecordCount.get(), + m_aFirstBtn.get(), + m_aPrevBtn.get(), + m_aNextBtn.get(), + m_aLastBtn.get(), + m_aNewBtn.get() + }; + + switch ( nType ) + { + case StateChangedType::Mirroring: + { + bool bIsRTLEnabled = IsRTLEnabled(); + for (vcl::Window* pWindow : pWindows) + pWindow->EnableRTL( bIsRTLEnabled ); + } + break; + + case StateChangedType::Zoom: + { + Fraction aZoom = GetZoom(); + + // not all of these controls need to know the new zoom, but to be sure ... + vcl::Font aFont(GetSettings().GetStyleSettings().GetToolFont()); + if (IsControlFont()) + aFont.Merge(GetControlFont()); + + for (vcl::Window* pWindow : pWindows) + { + pWindow->SetZoom(aZoom); + pWindow->SetZoomedPointFont(*pWindow, aFont); + } + + SetZoomedPointFont(*this, aFont); + + // rearrange the controls + ArrangeControls(); + } + break; + default:; + } +} + +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::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 pNewHeader = CreateHeaderBar(this); + pHeader->SetMouseTransparent(false); + + SetHeaderBar(pNewHeader); + SetMode(m_nMode); + SetCursorColor(Color(0xFF, 0, 0)); + + InsertHandleColumn(); +} + +DbGridControl::~DbGridControl() +{ + disposeOnce(); +} + +void DbGridControl::dispose() +{ + if (!IsDisposed()) + { + 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(aPoint.X()); + ArrangeControls(nX, static_cast(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 ) + { + if (IsControlBackground()) + { + GetDataWindow().SetBackground(GetControlBackground()); + GetDataWindow().SetControlBackground(GetControlBackground()); + GetDataWindow().SetFillColor(GetControlBackground()); + } + else + { + GetDataWindow().SetControlBackground(); + GetDataWindow().SetFillColor(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(aPoint.X()); + + ArrangeControls(nX, static_cast(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 ( IsEditing() ) + DeactivateCell(); + + m_aColumns.clear(); + + EditBrowseBox::RemoveColumns(); +} + +std::unique_ptr DbGridControl::CreateColumn(sal_uInt16 nId) +{ + return std::unique_ptr(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